当前位置: 首页 > news >正文

结合 Laravel 初步学习 GraphQL

按照官网所述的:

A query language for your API 一种用于 API 的查询语言

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

主要有以下几个特点:

  1. 请求你所要的数据不多不少。向你的 API 发出一个 GraphQL 请求就能准确获得你想要的数据,不多不少。 GraphQL 查询总是返回可预测的结果。
  2. 获取多个资源只用一个请求。GraphQL 查询不仅能够获得资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。
  3. 描述所有的可能类型系统。GraphQL API 基于类型和字段的方式进行组织,而非入口端点。你可以通过一个单一入口端点得到你所有的数据能力。GraphQL 使用类型来保证应用只请求可能的数据,还提供了清晰的辅助性错误信息。应用可以使用类型,而避免编写手动解析代码。
  4. API 演进无需划分版本。给你的 GraphQL API 添加字段和类型而无需影响现有查询。老旧的字段可以废弃,从工具中隐藏。通过使用单一演进版本,GraphQL API 使得应用始终能够使用新的特性,并鼓励使用更加简洁、更好维护的服务端代码。
  5. 使用你现有的数据和代码。GraphQL 让你的整个应用共享一套 API,而不用被限制于特定存储引擎。GraphQL 引擎已经有多种语言实现,通过 GraphQL API 能够更好利用你的现有数据和代码。你只需要为类型系统的字段编写函数,GraphQL 就能通过优化并发的方式来调用它们。

Demo

先写一个 Demo 来看看如何结合 Laravel 使用 GraphQL。

引入 rebing/graphql-laravel

composer require "rebing/graphql-laravel"
复制代码

因为 Laravel 5.5 开始,有「包自动发现」mp.weixin.qq.com/s/AD05BiKjP…功能,所以 Laravel 5.5 可以不用手动引入该 provider 和 aliase。之前的版本需要引入对应的 provider 和 aliase。

"extra": {
    "laravel": {
        "providers": [
            "Rebing\\GraphQL\\GraphQLServiceProvider"
        ],
        "aliases": {
            "GraphQL": "Rebing\\GraphQL\\Support\\Facades\\GraphQL"
        }
    }
}
复制代码

创建 Type 和 Query

Type: 通过 Type,可以帮助我们格式化查询结果的类型,主要有 boolean、string、float、int 等,同时也可以自定义类型

Query: 通过 Query,可以获取我们需要的数据。

在项目根目录创建 GraphQL 文件件用于存放 Type 和 Query

定义 UsersType:

<?php
/**
 * User: yemeishu
 */

namespace App\GraphQL\Type;

use App\User;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;

class UsersType extends GraphQLType
{
    protected $attributes = [
        'name' => 'Users',
        'description' => 'A type',
        'model' => User::class, // define model for users type
    ];

    // define field of type
    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => 'The id of the user'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => 'The email of user'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => 'The name of the user'
            ]
        ];
    }

    protected function resolveEmailField($root, $args)
    {
        return strtolower($root->email);
    }
}
复制代码

定义 Query:

<?php
/**
 * User: yemeishu
 */

namespace App\GraphQL\Query;

use App\User;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
use Rebing\GraphQL\Support\SelectFields;

class UsersQuery extends Query
{
    protected $attributes = [
        'name' => 'users',
        'description' => 'A query of users'
    ];

    public function type() {
        return Type::listOf(GraphQL::type('users'));
    }

    // arguments to filter query
    public function args()
    {
        return [
            'id' => [
                'name' => 'id',
                'type' => Type::int()
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::string()
            ]
        ];
    }

    public function resolve($root, $args, SelectFields $fields)
    {
        $where = function ($query) use ($args) {
            if (isset($args['id'])) {
                $query->where('id',$args['id']);
            }

            if (isset($args['email'])) {
                $query->where('email',$args['email']);
            }
        };
        $users = User::with(array_keys($fields->getRelations()))
            ->where($where)
            ->select($fields->getSelect())
            ->get();

        return $users;
    }
}
复制代码

配置 graphql.php

将写好的 UsersType 和 UsersQuery 注册到 GraphGL 配置文件中。

测试

我们主要有两种途径用于测试,第一种就是向测试 RESTful 接口一样,使用 Postman:

另一种方式就是利用 GraphiQL:

An in-browser IDE for exploring GraphQL. https://github.com/graphql/graphiql

这里我们使用 noh4ck/graphiql

// 1. 安装插件
composer require "noh4ck/graphiql:@dev"

// 2. 加入 provider
Graphiql\GraphiqlServiceProvider::class

// 3. 命令
artisan graphiql:publish
复制代码

配置文件可看出 route 为:/graphql-ui

运行结果:

还可以通过传入参数 (id: 1) 来筛选数据:

Mutation

通过 Demo,我们初步了解 GraphQL 的 Query 查询方法,接下来我们看看 Mutation 的用法。

如果说 Query 是 RESTful 的「查」,那么 Mutation 充当的作用就是「增、删、改」了。

在 GraphQL 文件夹下创建「Mutation」文件夹,存放和 Mutation 相关的类。

Create Mutation Class

<?php
/**
 * User: yemeishu
 * Date: 2018/4/3
 */

namespace App\GraphQL\Mutation;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Mutation;
use App\User;

class NewUserMutation extends Mutation
{
    protected $attributes = [
        'name' => 'NewUser'
    ];

    public function type()
    {
        return GraphQL::type('users');
    }

    public function args()
    {
        return [
            'name' => [
                'name' => 'name',
                'type' => Type::nonNull(Type::string())
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::nonNull(Type::string())
            ],
            'password' => [
                'name' => 'password',
                'type' => Type::nonNull(Type::string())
            ]
        ];
    }
    public function resolve($root, $args) {
        $args['password'] = bcrypt($args['password']);
        $user = User::create($args);

        if (!$user) {
            return null;
        }

        return $user;
    }
}
复制代码

Update Mutation Class

<?php
/**
 * User: yemeishu
 * Date: 2018/4/3
 */

namespace App\GraphQL\Mutation;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Mutation;
use App\User;

class UpdateUserMutation extends Mutation
{
    protected $attributes = [
        'name' => 'UpdateUser'
    ];

    public function type() {
        return GraphQL::type('users');
    }

    public function args() {
        return [
            'id' => [
                'name' => 'id',
                'type' => Type::nonNull(Type::int())
            ],
            'name' => [
                'name' => 'name',
                'type' => Type::nonNull(Type::string())
            ]
        ];
    }

    public function resolve($root, $args) {
        $user = User::find($args['id']);
        if (!$user) {
            return null;
        }
        $user->name = $args['name'];
        $user->save();
        return $user;
    }
}
复制代码

配置 graphql.php

把 NewUserMutation 和 UpdateUserMutation 加入 graphql mutation 配置中

测试

如上图,创建两个 mutation,可以选择任意一个看运行效果。

创建一个 User:

更新「id: 1」用户信息:

其中在 graphql-ui 界面,右上角还可以看到「Docs」,点开可以查看这两个 mutiation 的说明:

总结

通过简单的「增改查」User 来初步了解 GraphQL 的 Query 和 Mutation 的使用,接下来可以将 GraphQL 作为微服务的「网关」层的前一层来使用。

其中,推荐一篇文章给大家:微服务下使用GraphQL构建BFF | 洞见mp.weixin.qq.com/s/HSIp5PL-s…

「未完待续」

相关文章:

  • 实验三 类与对象(zxt)
  • 翻译:DECLARE HANDLER语句(已提交到MariaDB官方手册)
  • 窥探Node.js里的Stream
  • 给mybatis添加自动建表,自动加字段的功能
  • 如何夯实(Java)编程基础,并深入学习和提高
  • 大话测试与质量
  • 文顶顶虽老,博客尚在
  • BZOJ3998:[TJOI2015]弦论——题解
  • 3、第一个Appium测试
  • 【代码片段】Python发送带图片的邮件
  • @Autowired @Resource @Qualifier的区别
  • 区块链学习路线
  • Activity事件分发机制
  • ListT常用操作函数
  • Tomcat 的连接数与线程池
  • 【5+】跨webview多页面 触发事件(二)
  • Angular 4.x 动态创建组件
  • avalon2.2的VM生成过程
  • CSS实用技巧干货
  • ECS应用管理最佳实践
  • ES6系列(二)变量的解构赋值
  • express.js的介绍及使用
  • golang中接口赋值与方法集
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • Laravel 菜鸟晋级之路
  • MySQL主从复制读写分离及奇怪的问题
  • Promise面试题2实现异步串行执行
  • Redash本地开发环境搭建
  • spring + angular 实现导出excel
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • 高性能JavaScript阅读简记(三)
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 译自由幺半群
  • 自动记录MySQL慢查询快照脚本
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • const的用法,特别是用在函数前面与后面的区别
  • 阿里云移动端播放器高级功能介绍
  • #include
  • (12)Hive调优——count distinct去重优化
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (八)c52学习之旅-中断实验
  • (蓝桥杯每日一题)love
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • ***监测系统的构建(chkrootkit )
  • .NET CLR基本术语
  • .net 程序发生了一个不可捕获的异常
  • ??myeclipse+tomcat
  • [ C++ ] template 模板进阶 (特化,分离编译)
  • [20161214]如何确定dbid.txt
  • [20170705]lsnrctl status LISTENER_SCAN1
  • [Android View] 可绘制形状 (Shape Xml)
  • [CISCN2019 华东北赛区]Web2