Laravel GraphQL 為應用程序構建API
什么是GraphQL?
GraphQL是API的查詢語言,也是一個服務器端運行時,用於通過使用為數據定義的類型系統執行查詢。
GraphQL不綁定到任何特定的數據庫或存儲引擎,而是支持現有的代碼和數據。
它是由Facebook創建的,以滿足不斷增長的API消費需求,並已在主要語言中實施。
官網地址:http://graphql.org/ 需要翻牆!
中文官網: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/