garphql

在 Laravel 中使用 GraphQL

什么是GraphQL?

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

简单来说,GraphQL 不同于REST API,REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。查询方式类似下面这样子:

{
    user {
        id
        name
        job {
            name
            description
        }
    }
}

// 查询得到的数据格式是:

{
  "data": {
    "users": [
      {
        "id": 1,
        "name": "kwen",
        "job": [
          {
            "name": "前端开发工程师",
            "description": "前端前端"
          }
        ]
      },
      {
        "id": 2,
        "name": "kwen1",
        "job": [
          {
            "name": "PHP开发工程师",
            "description": "PHP"
          }
        ]
      }
    ]
  }
}

你可以在 这里 查看更多关于 GraphQL 的信息

在 Laravel 中使用 GraphQL

以下我会用一个简单的demo来演示如何使用

1、安装 Laravel

$ composer global require "laravel/installer"
$ laravel new laravel-graphql-test
$ cd laravel-graphql-test

我这里使用的是valet 作为开发环境,详细的安装也可以到文档中查看

2、安装 laravel-graphql package

修改composer.json

{
    "require": {
        "rebing/graphql-laravel": "~1.7"
    }
}

更新 composer

$ composer install
// 或者
$ composer update

添加 service provider

// 添加到app/config/app.php
Rebing\GraphQL\GraphQLServiceProvider::class,

并添加 facade

'GraphQL' => 'Rebing\GraphQL\Support\Facades\GraphQL',

生成配置文件

$ php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider"

然后就可以到 config/graphql.php查看配置信息了

3、创建数据模型

生成模型和数据库表迁移文件

$ php artisan make:model Job -m

Model created successfully.
Created Migration: 2018_02_14_152840_create_jobs_table

建立模型关系

// app/User.php
...
class User extends Authenticatable 
{
    ...
    public function job()
    {
        return $this->hasMany('App\Models\Job');
    }
}
// app/Job.php
...
class Job extends Model
{
    public function user()
    {
        return $this->belongsTo("App\Models\User");
    }
}

修改migration

// xxx_create_jobs_table.php
...
class CreateJobsTable extends Migration
{
    public function up()
    {
        Schema::create('jobs', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->string('name');
            $table->text('description')->nullable();
            $table->timestamps();
        });
    }
    ...
}

迁移 migration

$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2018_02_14_152840_create_jobs_table
Migrated:  2018_02_14_152840_create_jobs_table

4、创建 GraphQL 的 Query 和 Type

GraphQL 是一个基于类型系统来执行查询的,所以需要定义好暴露的查询接口 (Query) 以及 接口的类型 (Type)

Type 会帮助我们格式化查询结果的类型,一般为boolean、string、float、int等,另外还可以定义自定义类型

目录结构

GraphQL目录结构

​ 图为GraphQL目录结构

定义Type

// app/GraphQL/Type/UsersType.php

<?php
namespace App\GraphQL\Type;

use App\Models\User;
use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;

class UsersType extends GraphQLType
{
    protected $attributes = [
        'name' => 'Users',
        'description' => '用户',
        'model' => User::class
    ];

    /**
     * 定义返回的字段接口
     * @return array
     */
    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => '用户id'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => '用户名'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => '用户的email'
            ],
            'job' => [
                'type' => Type::listOf(GraphQL::type('jobs')),
                'description' => '用户的工作字段'
            ]
        ];
    }
}
// app/GraphQL/Type/JobsType.php

<?php
namespace App\GraphQL\Type;

use App\Models\Job;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;

class JobsType extends GraphQLType
{
    protected $attributes = [
        'name' => 'jobs',
        'description' => '工作',
        'model' => Job::class
    ];

    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => '工作id'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => '工作名'
            ],
            'description' => [
                'type' => Type::string(),
                'description' => '工作职责描述'
            ]
        ];
    }
}

定义查询接口 Query

// app/GraphQL/Query/UsersQuery.php

<?php

namespace App\GraphQL\Query;

use GraphQL;
use App\Models\User;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;

class UsersQuery extends Query
{
    protected $attributes = [
        'name' => 'users'
    ];

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

    /**
     * 接收参数的类型定义
     * @return array
     */
    public function args()
    {
        return [
            'id' => ['name' => 'id', 'type' => Type::int()],
            'email' => ['name' => 'email', 'type' => Type::string()],
            'limit' => ['name' => 'limit', 'type' => Type::int()],
        ];
    }

    /**
     * @param $root
     * @param $args 传入参数
     *
     * 处理请求的逻辑
     * @return mixed
     */
    public function resolve($root, $args)
    {
        $user = new User;

        if(isset($args['limit']) ) {
            $user =  $user->limit($args['limit']);
        }

        if(isset($args['id']))
        {
            $user = $user->where('id' , $args['id']);
        }

        if(isset($args['email']))
        {
            $user = $user->where('email', $args['email']);
        }

        return $user->get();
    }
}
// app/GraphQL/Query/JobsQuery.php

<?php

namespace App\GraphQL\Query;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;

class JobsQuery extends Query
{
    protected $attributes = [
        'name' => 'jobs'
    ];

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

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

5、测试结果

接下来就可以开始测试了

填充测试数据

因为数据库里面什么数据都没有,所以首先需要填充测试数据,这里使用的是 seed 进行填充

// database/seeds/UsersTableSeeder.php

...
class UsersTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'kwen',
            'email' => 'email@email.com',
            'password' => bcrypt('123456'),
        ]);
        DB::table('users')->insert([
            'name' => 'kwen1',
            'email' => 'email1@email.com',
            'password' => bcrypt('123456'),
        ]);
    }
}
// database/seeds/JobsTableSeeder.php

...
class JobsTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('jobs')->insert([
            'user_id' => 1,
            'name' => '前端开发工程师',
            'description' => '前端前端'
        ]);
        DB::table('jobs')->insert([
            'user_id' => 2,
            'name' => 'PHP开发工程师',
            'description' => 'PHP'
        ]);
    }
}
// database/seeds/DatabaseSeeder.php

...
class DatabaseSeeder extends Seeder
{
    public function run()
    {
         $this->call(UsersTableSeeder::class);
         $this->call(JobsTableSeeder::class);
    }
}

修改完这两个文件之后使用 artisan 命令进行填充

$ php artisan db:seed
Seeding: UsersTableSeeder
Seeding: JobsTableSeeder

安装测试工具

这里使用的是 GraphQL 可视化调试工具,专门针对 Laravel 的 noh4ck/laravel-graphiql

1、安装 laravel-graphiql

$ composer require "noh4ck/graphiql:@dev"

2、打开 config/app.php 并添加以下代码到 providers 中

Graphiql\GraphiqlServiceProvider::class

3、发布这个包并生成 config/graphiql.php配置文件

$ php artisan graphiql:publish

测试数据

运行 php artisan serve 然后打开http://127.0.0.1:8000/graphql-ui 就可以打开测试工具的界面了

测试数据

如果要查询某个特定 id 或者特定参数的 user ,则可以带参数进行查询

带参数查询

限定 2 个用户

限定用户的查询

所传参数的设置可以在app/GraphQL/Query/UsersType.php 中设置,resolve 方法里面就是设置参数逻辑的

总结

这篇文章简单地介绍了如何在 Laravel 中使用 GraphQL 作为 API 查询语言了,使用的是 noh4ck/laravel-graphiql ,但是使用中觉得这个包的还不够完美,如果在生成 Type 或者 Query的时候能用 artisan 命令就好了,我已经在github 上面提了 issue 并得到相关回复,应该很快就可以使用这些功能了。

有人说传统Restful API已死,GraphQL永生,GraphQL解决的就是Restful 的缺点,但同时GraphQL也存在很多性能的问题,GraphQL 真正要完全替代 Restful API 还有很长一段路要走,让我们拭目以待吧!

往后文章中还会继续介绍这个包的更多用法,例如如何修改数据、增加数据、删除数据还有授权认证authenticated等等,第一次写文章,希望能多多支持。

posted @ 2018-08-28 13:34  李傲强  阅读(557)  评论(0编辑  收藏  举报