結合 Laravel 初步學習 GraphQL

coding01發表於2018-04-03

結合 Laravel 初步學習 GraphQL

按照官網所述的:

A query language for your API 一種用於 API 的查詢語言

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

GraphQL 既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。 GraphQL 對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。

主要有以下幾個特點:

  1. 請求你所要的資料不多不少。向你的 API 發出一個 GraphQL 請求就能準確獲得你想要的資料,不多不少。 GraphQL 查詢總是返回可預測的結果。
  2. 獲取多個資源只用一個請求。GraphQL 查詢不僅能夠獲得資源的屬性,還能沿著資源間引用進一步查詢。典型的 REST API 請求多個資源時得載入多個 URL,而 GraphQL 可以通過一次請求就獲取你應用所需的所有資料。這樣一來,即使是比較慢的行動網路連線下,使用 GraphQL 的應用也能表現得足夠迅速。
  3. 描述所有的可能型別系統。GraphQL API 基於型別和欄位的方式進行組織,而非入口端點。你可以通過一個單一入口端點得到你所有的資料能力。GraphQL 使用型別來保證應用只請求可能的資料,還提供了清晰的輔助性錯誤資訊。應用可以使用型別,而避免編寫手動解析程式碼。
  4. API 演進無需劃分版本。給你的 GraphQL API 新增欄位和型別而無需影響現有查詢。老舊的欄位可以廢棄,從工具中隱藏。通過使用單一演進版本,GraphQL API 使得應用始終能夠使用新的特性,並鼓勵使用更加簡潔、更好維護的服務端程式碼。
  5. 使用你現有的資料和程式碼。GraphQL 讓你的整個應用共享一套 API,而不用被限制於特定儲存引擎。GraphQL 引擎已經有多種語言實現,通過 GraphQL API 能夠更好利用你的現有資料和程式碼。你只需要為型別系統的欄位編寫函式,GraphQL 就能通過優化併發的方式來呼叫它們。

Demo

先寫一個 Demo 來看看如何結合 Laravel 使用 GraphQL。

引入 rebing/graphql-laravel

composer require "rebing/graphql-laravel"
複製程式碼

因為 Laravel 5.5 開始,有「包自動發現」mp.weixin.qq.com/s/AD05BiKjP…功能,所以 Laravel 5.5 可以不用手動引入該 provider 和 aliase。之前的版本需要引入對應的 provider 和 aliase。

"extra": {
    "laravel": {
        "providers": [
            "Rebing\\GraphQL\\GraphQLServiceProvider"
        ],
        "aliases": {
            "GraphQL": "Rebing\\GraphQL\\Support\\Facades\\GraphQL"
        }
    }
}
複製程式碼

建立 Type 和 Query

Type: 通過 Type,可以幫助我們格式化查詢結果的型別,主要有 boolean、string、float、int 等,同時也可以自定義型別

Query: 通過 Query,可以獲取我們需要的資料。

在專案根目錄建立 GraphQL 檔案件用於存放 Type 和 Query

結合 Laravel 初步學習 GraphQL

定義 UsersType:

<?php
/**
 * User: yemeishu
 */

namespace App\GraphQL\Type;

use App\User;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;

class UsersType extends GraphQLType
{
    protected $attributes = [
        'name' => 'Users',
        'description' => 'A type',
        'model' => User::class, // define model for users type
    ];

    // define field of type
    public function fields()
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => 'The id of the user'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => 'The email of user'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => 'The name of the user'
            ]
        ];
    }

    protected function resolveEmailField($root, $args)
    {
        return strtolower($root->email);
    }
}
複製程式碼

定義 Query:

<?php
/**
 * User: yemeishu
 */

namespace App\GraphQL\Query;

use App\User;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
use Rebing\GraphQL\Support\SelectFields;

class UsersQuery extends Query
{
    protected $attributes = [
        'name' => 'users',
        'description' => 'A query of users'
    ];

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

    // arguments to filter query
    public function args()
    {
        return [
            'id' => [
                'name' => 'id',
                'type' => Type::int()
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::string()
            ]
        ];
    }

    public function resolve($root, $args, SelectFields $fields)
    {
        $where = function ($query) use ($args) {
            if (isset($args['id'])) {
                $query->where('id',$args['id']);
            }

            if (isset($args['email'])) {
                $query->where('email',$args['email']);
            }
        };
        $users = User::with(array_keys($fields->getRelations()))
            ->where($where)
            ->select($fields->getSelect())
            ->get();

        return $users;
    }
}
複製程式碼

配置 graphql.php

將寫好的 UsersType 和 UsersQuery 註冊到 GraphGL 配置檔案中。

結合 Laravel 初步學習 GraphQL

測試

我們主要有兩種途徑用於測試,第一種就是向測試 RESTful 介面一樣,使用 Postman:

結合 Laravel 初步學習 GraphQL

另一種方式就是利用 GraphiQL:

An in-browser IDE for exploring GraphQL. https://github.com/graphql/graphiql

這裡我們使用 noh4ck/graphiql

// 1. 安裝外掛
composer require "noh4ck/graphiql:@dev"

// 2. 加入 provider
Graphiql\GraphiqlServiceProvider::class

// 3. 命令
artisan graphiql:publish
複製程式碼

配置檔案可看出 route 為:/graphql-ui

結合 Laravel 初步學習 GraphQL

執行結果:

結合 Laravel 初步學習 GraphQL

還可以通過傳入引數 (id: 1) 來篩選資料:

結合 Laravel 初步學習 GraphQL

Mutation

通過 Demo,我們初步瞭解 GraphQL 的 Query 查詢方法,接下來我們看看 Mutation 的用法。

如果說 Query 是 RESTful 的「查」,那麼 Mutation 充當的作用就是「增、刪、改」了。

結合 Laravel 初步學習 GraphQL

在 GraphQL 資料夾下建立「Mutation」資料夾,存放和 Mutation 相關的類。

Create Mutation Class

<?php
/**
 * User: yemeishu
 * Date: 2018/4/3
 */

namespace App\GraphQL\Mutation;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Mutation;
use App\User;

class NewUserMutation extends Mutation
{
    protected $attributes = [
        'name' => 'NewUser'
    ];

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

    public function args()
    {
        return [
            'name' => [
                'name' => 'name',
                'type' => Type::nonNull(Type::string())
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::nonNull(Type::string())
            ],
            'password' => [
                'name' => 'password',
                'type' => Type::nonNull(Type::string())
            ]
        ];
    }
    public function resolve($root, $args) {
        $args['password'] = bcrypt($args['password']);
        $user = User::create($args);

        if (!$user) {
            return null;
        }

        return $user;
    }
}
複製程式碼

Update Mutation Class

<?php
/**
 * User: yemeishu
 * Date: 2018/4/3
 */

namespace App\GraphQL\Mutation;

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Mutation;
use App\User;

class UpdateUserMutation extends Mutation
{
    protected $attributes = [
        'name' => 'UpdateUser'
    ];

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

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

    public function resolve($root, $args) {
        $user = User::find($args['id']);
        if (!$user) {
            return null;
        }
        $user->name = $args['name'];
        $user->save();
        return $user;
    }
}
複製程式碼

配置 graphql.php

把 NewUserMutation 和 UpdateUserMutation 加入 graphql mutation 配置中

結合 Laravel 初步學習 GraphQL

測試

結合 Laravel 初步學習 GraphQL

如上圖,建立兩個 mutation,可以選擇任意一個看執行效果。

建立一個 User:

結合 Laravel 初步學習 GraphQL

更新「id: 1」使用者資訊:

結合 Laravel 初步學習 GraphQL

其中在 graphql-ui 介面,右上角還可以看到「Docs」,點開可以檢視這兩個 mutiation 的說明:

結合 Laravel 初步學習 GraphQL

總結

通過簡單的「增改查」User 來初步瞭解 GraphQL 的 Query 和 Mutation 的使用,接下來可以將 GraphQL 作為微服務的「閘道器」層的前一層來使用。

其中,推薦一篇文章給大家:微服務下使用GraphQL構建BFF | 洞見mp.weixin.qq.com/s/HSIp5PL-s…

「未完待續」

相關文章