GraphQL用語
Schema
- APIのこと。
- クライアントがサーバーにクエリを送信した時に、返却値として期待されるオブジェクトの型定義。
-
type
キーワードによってGraphQLオブジェクトの型を定義する(その集合がSchema)。 - 以下の例において、
id
,text
,done
,user
,createTodo
などを field(フィールド) と呼ぶ。
-
# graph/schema.graphqls
type Todo {
id: ID!
text: String!
done: Boolean!
user: User!
}
type User {
id: ID!
name: String!
}
type Query {
todos: [Todo!]!
}
input NewTodo {
text: String!
userId: String!
}
type Mutation {
createTodo(input: NewTodo!): Todo!
}
Resolver
- フィールド(
CreateTodo
, etc)の実装。 - クライアントが要求したフィールドの値を返却するための関数。
- フィールドをresolve(解決する)ので
resolver
。
- フィールドをresolve(解決する)ので
// graph/schema.resolvers.go
func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
todo := &model.Todo{
Text: input.Text,
ID: fmt.Sprintf("T%d", rand.Int()),
User: &model.User{ID: input.UserID, Name: "user " + input.UserID},
UserID: input.UserID,
}
r.todos = append(r.todos, todo)
return todo, nil
}
func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) {
return &model.User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
}
Query
- データの取得を行う言語。
- HTTP GETに相当。
- サーバーの
schema
で定義された「オブジェクトの型type
」に、クライアントから取得可能なfield
が定義されている。
query findTodos {
todos {
text
done
user {
name
}
}
}
queryのレスポンス
{
"data": {
"todos": [
{
"text": "todo",
"done": false,
"user": {
"name": "user 1"
}
}
]
}
}
Mutation
- データの作成・更新・削除を行う言語。
- HTTP POST/PUT/DELETEに相当。
mutation createTodo {
createTodo(input: { text: "todo", userId: "1" }) {
user {
id
}
text
done
}
}
mutationのレスポンス
{
"data": {
"createTodo": {
"user": {
"id": "1"
},
"text": "todo",
"done": false
}
}
}
Data source(ApolloServerを利用した場合)
- ApolloServerが、DBやREST APIなどから取得したデータをカプセル化し、キャッシュやエラー処理を行えるようにするためのクラス。
- 接続先毎に作成する。
-
resolver
から利用される。 - Data sourceの例
- RailsのREST APIのHTTPクライアント
- ElasticSearchクライアント
- DynamoDBクライアント
GraphQLとRESTの比較
REST | GraphQL | |
---|---|---|
参照 | リクエスト(GET) | クエリ(query) |
作成・更新・削除 | リクエスト(POST/PUT/DELETE) | クエリ(mutation) |
Pub/Sub | なし (WebSocketを使う場合が多い) |
クエリ(subscription) |
サーバの記述 | ルーティングとコントローラ | スキーマ(schema・type) / リゾルバ(resolver) (エンドポイントは1つになるためルーティングの定義は最初の一回を除いて不要(なはず)) |
REST API運用の課題
- サーバーサイドでユースケース毎にAPIが増える。
- クライアントサイドでドメインロジックを作ったり、状態を持つ必要性が出る。
GraphQLのメリット
- クライアントサイドとサーバーサイドのコミュニケーションコストの削減。
- グラフ構造でリレーションを表現できるので、サーバーサイドはユースケース毎のAPIを作る必要がなくなり、クライアントサイドでそのまま表示できるようなクエリを作れば良い。(?)
- クライアントサイドは利用可能な全ての状態がわかり、必要なデータを選択できる。
- GraphQLクライアント(Appolo、Relayなど)を利用すると、グラフ構造をキャッシュしてくれる。これにより、
- クライアントサイドは状態を持つ必要がなくなる。
GraphQLのデメリット
- クエリのパフォーマンス問題や脆弱性を生みやすい。
Securing Your GraphQL API from Malicious Queries
よくある誤解
Q. DB構造をクライアントにそのまま公開してしまうのでは?
A. Hasuraを使った場合、DB構造からGraphQLスキーマを自動生成するが、これはRESTでも同様。
参照