zoukankan      html  css  js  c++  java
  • 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
    RebingGraphQLGraphQLServiceProvider::class,

    并添加 facade

    'GraphQL' => 'RebingGraphQLSupportFacadesGraphQL',

    生成配置文件

    $ php artisan vendor:publish --provider="RebingGraphQLGraphQLServiceProvider"

    然后就可以到 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('AppModelsJob');
        }
    }
    // app/Job.php
    ...
    class Job extends Model
    {
        public function user()
        {
            return $this->belongsTo("AppModelsUser");
        }
    }

    修改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 AppGraphQLType;
    
    use AppModelsUser;
    use GraphQL;
    use GraphQLTypeDefinitionType;
    use FolkloreGraphQLSupportType 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 AppGraphQLType;
    
    use AppModelsJob;
    use GraphQLTypeDefinitionType;
    use FolkloreGraphQLSupportType 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 AppGraphQLQuery;
    
    use GraphQL;
    use AppModelsUser;
    use GraphQLTypeDefinitionType;
    use FolkloreGraphQLSupportQuery;
    
    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 AppGraphQLQuery;
    
    use GraphQL;
    use GraphQLTypeDefinitionType;
    use FolkloreGraphQLSupportQuery;
    
    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 中

    GraphiqlGraphiqlServiceProvider::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等等,第一次写文章,希望能多多支持。

  • 相关阅读:
    autoMapper dotnetcore webapi 自动添加映射 abp
    win10安装MongoDB提示 the domain,user name and/or password are incorrect. Remember to use "." for the domain if the account is on the local machine.
    webapi 重复提交问题
    webapi postman 415 错误
    sqlserver 更新通过 select 查询出的结果集
    2016-03至2016-08前端工作总结
    css笔记——css 实现自定义按钮
    javascript笔记——date以及datetime的比较
    node.js笔记——gulp
    javascript笔记——密码组合规则
  • 原文地址:https://www.cnblogs.com/qaing123/p/9547732.html
Copyright © 2011-2022 走看看