Laravel5.5 GraphQL 為應用程序構建API


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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM