Laravel5.5 GraphQL 为应用程序构建API

Laravel GraphQL 为应用程序构建API

什么是GraphQL?

GraphQL是API的查询语言,也是一个服务器端运行时,用于通过使用为数据定义的类型系统执行查询。

GraphQL不绑定到任何特定的数据库或存储引擎,而是支持现有的代码和数据。

它是由Facebook创建的,以满足不断增长的API消费需求,并已在主要语言中实施

官网地址:http://graphql.org/ 需要FQ!

中文官网:http://graphql.cn 翻译由掘金翻译计划的译者完成,在此感谢他们。

Types

任何 GraphQL 实现的核心都是描述它可以返回哪些类型的对象,在 GraphQL 类型系统中描述并在 GraphQL 模式中返回。例如,这里是一个用户类型,我们稍后会在这篇文章中使用。

type User {
  id: Integer
  name: String,
  email: String,
  password: String,
}

Query

GraphQL查询以声明方式描述发行者希望从履行 GraphQL 查询的人处获取哪些数据。例如,如果你想获得用户与 id 和 name 您可以查询它是这样的:

query UserNameAndIDQuery {
  users {
    id,
    name
  }
}

这将只给我们这样的用户的名称和ID:

{  
   "data":{  
      "users":[  
         {  
            "id":1,
            "name":"Garnet Little"
         },
         {  
            "id":2,
            "name":"Lisa Moen MD"
         }
      ]
   }
}

Mutation

关于GraphQL的大多数讨论都集中在数据获取上,但是任何完整的数据平台都需要一种方法来修改服务器端数据,而 mutation 可以做到这一点。这些是可以在数据库上执行创建,更新和删除的一组查询。

mutation {
    createUser( 
      name: "Admin", 
      email: "amin@example.com", 
      password:"123456",
      password_confirmation:"123456" 
    ) 
    { id, 
      email, 
      name 
    }
}

以上 mutation 将创建一个用户,并返回的ID,电子邮件和名称。

{
    "data": {
        "createUser": {
            "id": 1,
            "email": "admin@admin.com",
            "name": "admin"
        }
    }
}

现在让我们看看如何在 Laravel 应用程序中使用它,我将使用 Laravel 5.5 并实现 GraphQL 服务器,我将使用 laravel-graphql 包。这个PHP实现是围绕现有数据层和业务逻辑的一个简单包装。

它没有规定这些层是如何实现的,或者使用哪个存储引擎。相反,它提供了为现有应用程序创建 API 的工具。

Laravel中安装

Laravel-graphql github地址:https://github.com/Folkloreatelier/laravel-graphql

 

创建一个新的 Laravel 5.5 应用程序,配置数据库并使用 composer 安装 laravel-graphql 包

composer require folklore/graphql

添加门面的服务提供商和别名

'providers' => [
    ...
    Folklore\GraphQL\ServiceProvider::class,
]

....
'aliases' => [
    ....
    'GraphQL' => Folklore\GraphQL\Support\Facades\GraphQL::class,
]

发布GraphQL配置文件

php artisan vendor:publish --provider="Folklore\GraphQL\ServiceProvider"

完成安装,一切都设置好了。继续生成模型和迁移文件。这里我们用Laravel自带的users迁移文件,配置好项目中的 .env 文件,连接上数据库,执行迁移命令。

php artisan migrate

用户类型

让我们来定义 UserType,我们需要创建我们的类 app/GraphQL/Type/UserType.php

<?php

namespace App\GraphQL\Type;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;

class UserType extends GraphQLType {

    protected $attributes = [
        'name' => 'User',
        'description' => 'A user'
    ];

    /*
     * Uncomment following line to make the type input object.
     * http://graphql.org/learn/schema/#input-types
     */
    // protected $inputObject = true;

    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => 'The id of the user'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => 'The name of user'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => 'The email of user'
            ],
            'created_at' => [
                'type' => Type::string(),
                'description' => 'Creation datetime'
            ],
            'updated_at' => [
                'type' => Type::string(),
                'description' => 'Updating datetime'
            ]
        ];
    }

    // If you want to resolve the field yourself, you can declare a method
    // with the following format resolve[FIELD_NAME]Field()
    protected function resolveEmailField($root, $args)
    {
        return strtolower($root->email);
    }

    protected function resolveCreatedAtField($root, $args)
    {
        return (string) $root->created_at;
    }
}

让我来解释一下怎么回事,GraphQL 需要2件事情来为一个字段返回数据。

第一个是 fields 第二个是 resolver 从该数据库获取数据的函数。在上面的类fields()方法中,我们为用户返回一个字段模式,只有在这里添加的字段将由GraphQL API返回。

而下面的fields()我们有解析器覆盖,例如我用resolveEmailField()方法格式化电子邮件,使其小写。就像Eloquent模型中的Accessor,在这之后我们有一些嵌套的资源tweets和profile,它们分别由resolveTweetsField()方法和方法解析 resolveProfileField()。

一旦你定义了所有的类型,你需要将它们添加到数组config/graphql.php下的文件中  types,那么GraphQL将如何知道可用的类型。

'types' => [
    'User' => App\GraphQL\Type\UserType::class,
],

现在我们有我们的类型,让我们定义我们的查询,以便我们可以通过使用GraphQL API调用访问数据。

User Query

我们想要创建一个只用于读取数据的查询。让我们定义一个访问用户,在下面的命名空间下创建一个类。

<?php

namespace App\GraphQL\Query;

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

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

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

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

    public function resolve($root, $args)
    {
        $user = new User;
        // check for limit
        if( isset($args['first']) ) {
            $user =  $user->limit($args['first'])->latest('id');//默认情况下,结果集根据 created_at 字段进行排序 这里我们根据id排序
        }

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

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

        return $user->get();
    }
}

为了简单起见,我已经在方法中添加了所有的解析器数据获取逻辑,您应该考虑一个服务类来委托获取数据,以便您可以添加缓存等。

这看起来与UserType非常相似,但它将用于获取实际的数据,所以首先,我们定义了我们要在type()方法中返回的Type ,在这种情况下它将会是Type::listOf(GraphQL::type('User'))

接下来我们定义这个查询在args()方法中可以采用的所有参数在这里,我们有id我们可以用来筛选用户的ID,email为相同的first,将被用来限制结果的数量。

一旦你定义了你的查询,让我们再次config/graphql.php在模式默认查询数组中添加它  

'schemas' => [
    'default' => [
        'query' => [
            'users' => App\GraphQL\Query\UsersQuery::class
           ...
        ],
    ]
]

GraphQL users query

现在我们可以打开浏览器并获取用户数据。让我们获取所有的用户 id 和 name,默认情况下,你可以在 http://localhost/graphql 路由上访问,你可以在graphql.php配置文件中更改此路由。

以下是我们的查询的样子:

query getUserNameAndId {
    users{
     id,
     name
    }
}

url请求是这样的:

http://localhost/graphql?query=query+getUserNameAndId{users{id,name}}

返回的结果是这样的:

{
    "data": {
        "users": [
            {
                "id": 1,
                "name": "Saqueib Ansrai"
            },
            {
                "id": 2,
                "name": "admin"
            }
        ]
    }
}

如果你做的一切正确,你会得到用户的名单,如果有什么错误,你会得到一个错误的消息。

Limit Result

如果您还记得在查询定义中,我们有一些参数,让我们使用它们。首先让我们将结果限制为5个用户,通过传递first:5获取。

query getUserNameAndId {
    users(first: 5){
     id,
     name
    }
}

Request URL

http://localhost/graphql?query=query+getUserNameAndId{users(first:5){id,name}}

通过ID或email查找用户

query getUserById {
    users(id:2){
     id,
     name
    }
}

query getUserByEmail {
 users(email:"saqueib@example.com"){
 id,
 name
 }
}

Requests URL

http://localhost/graphql?query=query+getUserById{users(id:5){id,name}}

http://localhost/graphql?query=query+getUserByEmailId{users(email:"saqueib@example.com"){id,name}}

GraphQL查询的强大功能

正如你所看到的,就你所需要的而言,你有很大的灵活性,如果你在REST API中做了同样的事情,你可能需要3个不同的HTTP请求来获得你需要的所有东西,或者在API上创建一些别名端点得到userWithTweet和另一个userWithProfile由于数据需求已经改变,所以更改应用程序的前端将会变得更加困难,现在您可能还需要另一个API端点userProfileAndTweets正如你所看到的,它很快就会变得非常混乱。但是对于GraphQL,您不需要任何其他端点,它很可能将是单个端点,查询以声明方式描述发行者希望获取的数据。

现在我们对如何获取数据有了一个很好的理解,但是如何对数据进行更改或者保存新记录呢?

GraphQL中的Mutation

让我们来定义的mutation  createUser,  updateUser和  deleteUser

让我们创建一个文件,app/GraphQL/Mutation/CreateUserMutation.php并添加下面的代码。

UserCreate Mutation

<?php

namespace App\GraphQL\Mutation;

use GraphQL;
use App\User;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;

class CreateUserMutation extends Mutation {

    protected $attributes = [
        'name' => 'createUser'
    ];

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

    public function rules()
    {
        return [
            'email'    => 'required|string|email|max:255|unique:users',
            'name'     => 'required|string|min:2',
            'password' => 'required|string|min:6|confirmed',
        ];
    }

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

    public function resolve($root, $args)
    {
        $fields = isset($args['password'])
                ? array_merge($args, ['password' => bcrypt($args['password'])])
                : $args;
        
        return User::create($args);
    }
}

mutation需要改变数据,所以它有一个 rules()方法来验证数据,你可以使用laravel验证和解析函数来完成数据库中的数据操作。在这种情况下,如果数据有效,就会创建一个用户。

正如我们为查询所做的那样,让我们config/graphql.php在模式默认的mutation数组下的文件中添加mutation

schemas' => [
    'default' => [
        'query' => [
            'users' => App\GraphQL\Query\UsersQuery::class
            ...
        ],
        'mutation' => [
            'createUser' => App\GraphQL\Mutation\CreateUserMutation::class,
            'updateUser' => App\GraphQL\Mutation\UpdateUserMutation::class,
            'deleteUser' => App\GraphQL\Mutation\DeleteUserMutation::class
        ]
    ]
]

UserDelete Mutation

在 delete mutation 中,你只需要传一个 id 值,就可以删除一个用户:

<?php

namespace App\GraphQL\Mutation;

use GraphQL;
use App\User;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;

class DeleteUserMutation extends Mutation {

    protected $attributes = [
        'name' => 'deleteUser'
    ];

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

    public function rules()
    {
        return [
            'id'    => 'required|int',
        ];
    }

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

    public function resolve($root, $args)
    {
        if( $user = User::findOrFail($args['id']) ) {
            $user->delete();
            return $user;
        }
    }
}

现在操作将是这样的:

mutation deleteUserById{
    deleteUser(
        id:2
    )
    {
        id,
        email,
        name
    }
}

将删除ID为2的用户,并返回已删除的用户ID,姓名和电子邮件。

Requests URL

http://localhost/graphql?query=mutation+deleteUserById{deleteUser(id:2){id,email,name}}

UserUpdate Mutation

 

<?php

namespace App\GraphQL\Mutation;

use GraphQL;
use App\User;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;

class UpdateUserMutation extends Mutation {

    protected $attributes = [
        'name' => 'createUser'
    ];

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

    public function rules()
    {
        return [
            'id'           => 'required|int',
        ];
    }

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

    public function resolve($root, $args)
    {
        $user = User::find($args['id']);

        if(! $user)
        {
            return null;
        }

        // update user
        $fields = isset($args['password'])
                ? array_merge($args, ['password' => bcrypt($args['password'])])
                : $args;

        $user->update($fields);

        return $user;
    }
}

请求是这样的:

mutation updateUsersPassword{
    updateUser(
        id:2,
        passwrod:"123456"
    )
    {
        id,
        email,
        name
    }
}

将更新ID为2的用户的password,并返回已用户ID,姓名和电子邮件。

 Requests URL

http://localhost/graphql?query=mutation+updateUsersEmail{updateUser(id:2,password:"123456"){id,email,name}}

因此,我们在GraphQL中完成了一个完整的CRUD操作。

 

http://www.qcode.in/build-api-for-twitter-like-app-using-graphql-in-laravel/

posted @ 2018-01-17 18:10  丶老中医  阅读(2976)  评论(0编辑  收藏  举报
一切已经开始©2018 丶老中医