在 Laravel 5.7 和 Vue 2.5 中使用 GraphQL 查詢語言

前言

本文為「GraphQL Laravel & Vue」教學影片的學習筆記。

環境

  • macOS

後端

建立後端專案

新增 Laravel 專案。

1
laravel new booksql-laravel

安裝 nuwave/lighthouse 套件。

1
composer require nuwave/lighthouse

發布資源。

1
2
php artisan vendor:publish --provider="Nuwave\Lighthouse\Providers\LighthouseServiceProvider" --tag=schema
php artisan vendor:publish --provider="Nuwave\Lighthouse\Providers\LighthouseServiceProvider" --tag=config

修改 config/lighthouse.php 檔中 models 指定的命名空間。

1
2
3
4
5
6
7
8
'namespaces' => [
'models' => 'App',
'queries' => 'App\\Http\\GraphQL\\Queries',
'mutations' => 'App\\Http\\GraphQL\\Mutations',
'interfaces' => 'App\\Http\\GraphQL\\Interfaces',
'unions' => 'App\\Http\\GraphQL\\Unions',
'scalars' => 'App\\Http\\GraphQL\\Scalars',
],

使用範例

下載 lighthouse-tutorial 範例。

1
2
git clone https://github.com/nuwave/lighthouse-tutorial.git
cd lighthouse-tutorial

或在新專案安裝 nuwave/lighthouse 套件。

1
composer require nuwave/lighthouse

建立設定檔。

1
cp .env.example .env

生成金鑰。

1
php artisan key:generate

安裝相依套件。

1
composer install

執行遷移。

1
php artisan migrate

新增填充。

1
2
php artisan tinker
>>> factory('App\Comment', 20)->create()

啟動伺服器。

1
php artisan serve

前往 http://127.0.0.1:8000 瀏覽。

跨域資源共享

安裝 laravel-cors 套件。

1
composer require barryvdh/laravel-cors

修改 config/lighthouse.php 檔:

1
2
3
4
5
6
'route' => [
'prefix' => '',
'middleware' => [
\Barryvdh\Cors\HandleCors::class,
]
],

安裝開發工具

安裝 GraphQL Playground 開發工具。

1
brew cask install graphql-playground

輸入網址:http://127.0.0.1:8000/graphql

或安裝 Laravel GraphQL Playground 網頁開發工具。

1
composer require --dev mll-lab/laravel-graphql-playground

前往 http://127.0.0.1:8000/graphql-playground 瀏覽。

架構

查看 routes/graphql/schema.graphql 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
"""This is a custom built-in Scalar type from LightHouse. It handles Carbon dates"""
scalar DateTime @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime")

type User {
id: ID!
name: String!
email: String!
created_at: DateTime!
updated_at: DateTime!
posts: [Post] @hasMany
}

type Post {
id: ID!
title: String!
content: String!
user: User! @belongsTo
comments: [Comment] @hasMany
}

type Comment {
id: ID!
reply: String!
post: Post! @belongsTo
}

type Query {
users: [User] @all
user(id: Int! @eq): User @find
posts: [Post] @all
post(id: Int! @eq): Post @find
}

執行查詢。

1
2
3
4
5
6
7
8
9
10
11
12
query {
post(id: 1) {
title
user {
name
email
}
comments {
reply
}
}
}

新增修改。

1
2
3
4
5
6
7
type Mutation {
createUser(
name: String! @rules(apply: ["required", "min:4"]),
email: String! @rules(apply: ["email", "unique:users"]),
password: String! @bcrypt,
): User! @create
}

執行修改。

1
2
3
4
5
6
7
8
9
10
mutation {
createUser(
name:"Test",
email:"[email protected]",
password: "secret",
) {
id
name
}
}

新增查詢類別

新增一個查詢類別。

1
php artisan lighthouse:query LatestPost

修改 app/Http/GraphQL/Queries/LatestPost.php 檔:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace App\Http\GraphQL\Queries;

use App\Post;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;

class LatestPost
{
/**
* Return a value for the field.
*
* @param null $rootValue Usually contains the result returned from the parent field. In this case, it is always `null`.
* @param array $args The arguments that were passed into the field.
* @param GraphQLContext|null $context Arbitrary data that is shared between all fields of a single query.
* @param ResolveInfo $resolveInfo Information about the query itself, such as the execution state, the field name, path to the field from the root, and more.
*
* @return mixed
*/
public function resolve($rootValue, array $args, GraphQLContext $context = null, ResolveInfo $resolveInfo)
{
return Post::all()->last();
}
}

修改 routes/graphql/schema.graphql 檔:

1
2
3
type Query {
latestPost: Post
}

執行查詢。

1
2
3
4
5
query {
latestPost {
title
}
}

前端

建立前端專案

1
vue create vue-apollo

安裝套件。

1
2
cd vue-apollo
vue add apollo

啟動伺服器。

1
npm run serve

前往 http://localhost:8080 瀏覽。

設定

修改 src/vue-apollo.js 檔:

1
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:8000/graphql';

執行查詢。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gql from 'graphql-tag';

export default {
data() {
return {
users: [],
user: '',
};
},
apollo: {
users: gql`{
users {
name
email
}
}`,
},
};

執行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
methods: {
createUser() {
this.$apollo.mutate({
mutation: gql`mutation {
createUser(
name:"Test2",
email:"[email protected]",
password: "secret",
) {
id
name
}
}`,
});
},
},