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/