本篇文章帶大家了解一下GraphQL,并詳細介紹PHP中安裝和使用GraphQL的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。
關(guān)于 GraphQL
GraphQL 是一種現(xiàn)代化的 HTTP API 接口構(gòu)建方式,客戶端可以按需
查詢需要的數(shù)據(jù)。
GraphQL 可以提升 API 調(diào)用的靈活性,我們可以像寫數(shù)據(jù)庫查詢語句一樣來請求 API 來獲取所需要的數(shù)據(jù),這對構(gòu)建復雜的 API 查詢來說非常有用。
與REST對比
REST的核心思想就是資源,每個資源都能用一個URL來表示,你能通過一個GET請求訪問該URL從而獲取該資源。根據(jù)當今大多數(shù)API的定義,你很有可能會得到一份JSON格式的數(shù)據(jù)響應(yīng),整個過程大概是這樣:
GET /user/1 { "username":"姓名", "age":20, "sex":"男" }
GET /book/1 { "book":"書名", "author":"作者", "country":"中國" }
從上面的示例可以看出,如果前端需要user/1
和book/1
的時候需要調(diào)用2次
接口,并且如果前端只需要user/1
里面的username
,而上面的接口獲取了username
以外的數(shù)據(jù),那么對于前端而言,除 username
之外的數(shù)據(jù)無處可用,造成了資源的浪費。
如果我們使用GraphQL
來進行查詢的話,與REST方式相比,只需要調(diào)用一次并且可以查詢我們指定的字段,避免了資源的浪費,并且更加高效。
query { user(id:1) { username } book(id:1){ book, author, country } }
推薦學習:《PHP視頻教程》
安裝graphql-php包
composer require webonyx/graphql-php
開始
1、安裝完成之后,我們先編寫一個簡單示例,來看看graphql-php怎么用,具體代碼如下:這段代碼中,我們定義了一個名為phoneNumber
的字段,然后通過postman來調(diào)用我們編寫的代碼。
<?php require_once __DIR__ . '/vendor/autoload.php'; use GraphQLTypeSchema; use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; use GraphQLGraphQL; $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'phoneNumber' => [ 'type' => Type::int(), 'resolve' => function () { return 1875555555; } ] ], ]); $schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { $rootValue = ['prefix' => 'prefix: ']; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); $output = $result->toArray(); } catch (Exception $e) { $output = [ 'errors' => [ [ 'message' => $e->getMessage() ] ] ]; } header('Content-Type: application/json'); echo json_encode($output);
2、使用postman來調(diào)用我們剛剛編寫的代碼,以下是我們查詢結(jié)果的示例
介紹
從上面的示例中,我們可以看到示例主要引入了4個類
use GraphQLTypeSchema; use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; use GraphQLGraphQL;
Schema 類
Schema 是類型層次結(jié)構(gòu)的容器,它接受構(gòu)造函數(shù)中的根類型并向內(nèi)部 GrahpQL 工具提供接收你的類型信息的方法。
配置選項
包含以下選項的數(shù)組:
Option | Type | Notes |
---|---|---|
query | ObjectType |
必須。 讀取 API 中包含根級字段的對象類型 (通常命名為 "Query"),用于讀取數(shù)據(jù) |
mutation | ObjectType |
寫入 API 中包含根級字段的對象類型 (通常命名為 "Mutation"),數(shù)據(jù)變更時會用到 |
subscription | ObjectType |
保留用于將來的描述實現(xiàn)。目前表現(xiàn)為 graphql-js 自檢查詢的兼容,用于各種客戶端 (如 Relay 或 GraphiQL) |
directives | Directive[] |
默認包含內(nèi)建指令 @skip 和 @include 。
如果你傳遞自定義指令并且依然想使用內(nèi)建指令,請聲明添加它們。例如: array_merge(GraphQL::getStandardDirectives(), [$myCustomDirective]); |
types | ObjectType[] |
對象類型類表,它在靜態(tài) schema 解析期間是不能被 graphql-php 發(fā)現(xiàn)的。
大多數(shù)情況下,對象類型未曾在字段中被直接引用,但它依然是 schema 的一部分時會用到,因為它實現(xiàn)了一個在 resolveType 中調(diào)用解析為此對象類型的接口。 請注意,您在此處無需傳遞所有類型 ,它只是具體用例的解決方法。 |
typeLoader | callable |
function($name) 返回給定的類型實例名稱。 多次調(diào)用情況下,必須返回同樣的實例。 查閱下文延遲類型加載部分。 |
ObjectType類
GraphQLTypeDefinitionObjectType
對象類型是典型的 GraphQL 應(yīng)用程序中使用最頻繁的基元。
配置選項
Option | Type | Notes |
---|---|---|
name | string |
必須。 Schema 中此對象的唯一名稱 |
fields | array or callable |
必須。 描述對象字段或可調(diào)用返回此類數(shù)組的數(shù)組。 |
description | string |
呈現(xiàn)于客戶端的參數(shù)文本說明(例如:用于 GraphiQL 自動生成文檔 ) |
interfaces | array or callable |
此類型實現(xiàn)的接口列表或返回此類列表的可調(diào)用接口。 |
內(nèi)置標量類型
<?php use GraphQLTypeDefinitionType; // 內(nèi)置標量類型 Type::string(); // String 類型 Type::int(); // Int 類型 Type::float(); // Float 類型 Type::boolean(); // Boolean 類型 Type::id(); // ID 類型
字段參數(shù)
GraphQL 對象類型上的所有字段都有 0 個或多個參數(shù),使用在 args 的字段定義上。每個參數(shù)數(shù)組參考以下說明:
Option | Type | Notes |
---|---|---|
name | string |
必須。 參數(shù)名稱。 為空時,使用 args 數(shù)組鍵值 |
type | Type |
必須。 |
description | string |
呈現(xiàn)于客戶端的參數(shù)文本說明 |
defaultValue | scalar |
當前參數(shù)默認值 |
示例
$queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'phoneNumber' => [ 'type' => Type::int(), 'resolve' => function () { return 1875555555; } ] ], ]);
GraphQL 類
GraphQL類主要在查詢的時候用到,我們可以用 GraphQL::executeQuery 方法來執(zhí)行查詢
executeQuery 方法的參數(shù)說明
參數(shù) | 類型 | 說明 |
---|---|---|
schema | GraphQLTypeSchema |
必須。 Schema應(yīng)用實例 |
queryString | string or GraphQLLanguageASTDocumentNode |
必須。 解析,驗證并執(zhí)行現(xiàn)有的 GraphQL 查詢字符。 如果在執(zhí)行之前解析其他查詢,則在此處傳遞相應(yīng)的 AST 文檔節(jié)點來避免新的解析。 |
rootValue | mixed |
表示數(shù)據(jù)圖結(jié)構(gòu)的基礎(chǔ)值。作為Query type 字段解析傳遞的第一個參數(shù)。如果現(xiàn)有該值已被 Query type 解析過,則可忽略或設(shè)置為 null 值。 |
context | mixed |
字段解析器的共享信息。 常用來傳遞已登錄用戶信息,位置詳情等。
它將用在所有字段解析器的第 3 個參數(shù)。 |
variableValues | array |
變量的映射,該值將隨同查詢字符串一起傳遞。請查閱 GraphQL官網(wǎng)查詢變量的相關(guān)。 |
operationName | string |
指定請求方可執(zhí)行的操作, 防止條件查詢字符包含多級操作。 |
fieldResolver | callable |
Schema 參數(shù) schema 中未實現(xiàn)的解析器函數(shù)。 |
validationRules | array |
查詢驗證規(guī)則組,默認所有規(guī)則??諗?shù)組將跳過查詢驗證 (對于持久化查詢將會比較方便,查詢會在持久化之前默認已驗證,并在執(zhí)行期間假設(shè)符合規(guī)則)。 |
use GraphQLGraphQL; $result = GraphQL::executeQuery( $schema, $queryString, $rootValue = null, $context = null, $variableValues = null, $operationName = null, $fieldResolver = null, $validationRules = null );
簡單示例
我們介紹完GraphQL幾個概念之后,用幾個簡單的示例帶大家來體驗一下。
普通示例
在這個示例中我們定義了2個字段,分別是phoneNumber
和echo
,其中phoneNumber為 Type::int()
類型,echo
為Type::string()
類型,同時echo
字段帶有一個參數(shù)為message
<?php require_once __DIR__ . '/vendor/autoload.php'; use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; use GraphQLGraphQL; use GraphQLTypeSchema; $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'phoneNumber' => [ 'type' => Type::int(), 'resolve' => function () { return 1875555555; } ], 'echo' => [ 'type' => Type::string(), 'args' => [ 'message' => Type::string(), ], 'resolve' => function ($root, $args) { return 'echo msg result:' . ($args['message'] ?? 'nothing'); } ], ], ]); $schema = new Schema([ 'query' => $queryType ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { $rootValue = ['prefix' => 'prefix: ']; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); $output = $result->toArray(); } catch (Exception $e) { $output = [ 'errors' => [ [ 'message' => $e->getMessage() ] ] ]; } header('Content-Type: application/json'); echo json_encode($output);
執(zhí)行示例代碼結(jié)果
我們可以看到,在請求時我們傳了phoneNumber
和echo
兩個字段,并且message
為test
。
對象示例
我們在上面說過,對象類型是典型的 GraphQL 應(yīng)用程序中使用最頻繁的基元,一個對象類型里面可以包含寧外一個對象類型,我們可以新定義一個名為$userType
的ObjectType
,然后在oneUser
指定它的類型為$userType
,這樣我們執(zhí)行查詢的時候,oneUser
就會返回一個對象。
<?php require_once __DIR__ . '/vendor/autoload.php'; use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; use GraphQLGraphQL; use GraphQLTypeSchema; $userType = new ObjectType([ 'name' => 'userType', 'description' => '用戶詳情', 'fields' => [ 'uid' => [ 'type' => Type::int(), 'description' => '用戶ID' ], 'name' => Type::string() ] ]); $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'oneUser' => [ 'type' => $userType, // 我們這里指定type為我們上面創(chuàng)建的$userType 'description' => '用戶列表', 'args' => [ 'uid' => [ 'type' => Type::int(), 'defaultValue' => 222 ] ], 'resolve' => function($root, $args) { return [ "uid" => $args['user_id'] ?? 3, "name" => "xzl", ]; } ], ] ]); $schema = new Schema([ 'query' => $queryType ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { $rootValue = ['prefix' => 'prefix: ']; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); $output = $result->toArray(); } catch (Exception $e) { $output = [ 'errors' => [ [ 'message' => $e->getMessage() ] ] ]; } header('Content-Type: application/json'); echo json_encode($output);
執(zhí)行示例代碼結(jié)果
列表示例
在平時的開發(fā)請求中,我們從后端接口獲取數(shù)據(jù)的時候,大部分都是以列表的形式返回的,我們可以通過Type::listOf
方法來指定我們返回的字段是一個列表。
<?php require_once __DIR__ . '/vendor/autoload.php'; use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; use GraphQLGraphQL; use GraphQLTypeSchema; class User { // 模擬從數(shù)據(jù)庫取數(shù)據(jù) public static function getUserLimit($limit) { $user = [ [ "uid" => 1, "name" => "name1" ], [ "uid" => 2, "name" => "name2" ], [ "uid" => 3, "name" => "name3" ], [ "uid" => 4, "name" => "name4" ] ]; return array_slice($user, 0, $limit); } } $userType = new ObjectType([ 'name' => 'userType', 'description' => '用戶詳情', 'fields' => [ 'uid' => [ 'type' => Type::int(), 'description' => '用戶ID' ], 'name' => Type::string() ] ]); $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'users' => [ 'type' => Type::listOf($userType), 'description' => '用戶列表', 'args' => [ 'limit' => [ 'type' => Type::int(), 'description' => '限制條數(shù)', 'defaultValue' => 10 ] ], 'resolve' => function($root, $args) { return User::getUserLimit($args['limit']); } ] ] ]); $schema = new Schema([ 'query' => $queryType ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { $rootValue = ['prefix' => 'prefix: ']; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); $output = $result->toArray(); } catch (Exception $e) { $output = [ 'errors' => [ [ 'message' => $e->getMessage() ] ] ]; } header('Content-Type: application/json'); echo json_encode($output);
執(zhí)行示例代碼結(jié)果
從上面結(jié)果可以看到,我們傳了limit
參數(shù)為2,最終從我們模擬的數(shù)據(jù)里面取出了2條數(shù)據(jù)
使用類型語言
在上面的示例中,如果我們代碼返回的數(shù)據(jù)比較復雜時,需要編寫大量的代碼,通過GraphQL類型語言,我們可以減少代碼量,使代碼看上去更加簡潔,這是一個用 GraphQL 類型語言定義的簡單 Schema示例。
<?php require_once __DIR__ . '/vendor/autoload.php'; use GraphQLGraphQL; use GraphQLUtilsBuildSchema; // graph.graphql 文件內(nèi)容 $graph = <<<GRAPH schema { query: Query } type Query { graph_test: String echo(message: String): String show_test: Show show_test_arr: [Show] } type Show { content: String! text: String! } GRAPH; $schema = BuildSchema::build($graph); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { $rootValue = [ 'sum' => function($rootValue, $args, $context) { return $args['x'] + $args['y']; }, 'echo' => function($rootValue, $args, $context) { return $rootValue['prefix'] . ($args['message'] ?? 'no echo'); }, 'show_test' => function($rootValue, $args, $context) { return [ 'content' => 'show_content', 'text' => 'xxxx xxx' ]; }, 'show_test_arr' => function($rootValue, $args, $context) { return [ [ 'content' => 'show_content', 'text' => 'xxxx xxx' ], [ 'content' => 'show_content_2', 'text' => 'xxxx xxx_2' ] ]; }, 'prefix' => 'from test:', "graph_test" => "graphql_test" ];; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); $output = $result->toArray(); } catch (Exception $e) { GraphQLServerStandardServer::send500Error($e); } header('Content-Type: application/json'); echo json_encode($output);
執(zhí)行示例代碼結(jié)果
參考
graphql.cn/learn/
learnku.com/docs/graphq…