【めっちゃ便利!】GraphQLについてざっくり理解する

6 min read読了の目安(約5400字

はじめに

今回は、会社で学んだ知識のoutputとして、GraphQLについての記事を執筆しようと思います。
GraphQLってなんなの?という人に向けての記事になるので、見ていただけると幸いです。

想定読者

  • GraphQLって聞いたことはあるけど、なんだか分からない人
  • APIを少しは触ったことがあるひと
  • (サンプルコードを実行したい人は)dockerの基礎が分かる人(go+ gqlgenを使用します。)

では、早速本題です。

で、GraphQLってなんなの?

GraphQLはすごく簡単に言うと、

FaceBookが作った新しいAPIの規格!!

記事を読んでくださっている皆さんはよく見るAPIは
RESTfulAPIなのではないかと思います。

GraphQLは新しいAPI規格と言うだけあって、
RESTfulAPIとはかなり違った書き方、考え方になっています。

ここから、
GraphQLについて、RESTfulAPIと比較しながら紹介できればと思います。

RESTful APIと何が違うの?

こちらは、RESTfulAPIとGraphQLの違いを表した図になります。

細かく言うと違いはたくさんあるのですが、、、

大きく分けて、違いは2つです。

  1. エンドポイントの数
  2. データの追加、更新、削除などの考え方

もう少し詳しく見ていきましょう。

1. エンドポイントの数

上の比較図を見てもらえればわかると思うのですが、エンドポイントの数が違います。

RESTfulAPIだと・・・・

students,courses, instructorsのようにリソース毎にエンドポイントが設定されているのがわかります。
一方で、

GraphQLの場合・・・

リソースの数に関わらず、エンドポイントが一つになっていることがわかると思います。
何で一つでいいの? って思う方もいらっしゃると思うのですが、
これは、クエリパラメータ
によって取得したい値やリソースを選択することができるからです。
比較図はこんな感じ

Restful API GraphQL
エンドポイント リソース毎に作成する必要がある。 基本的に一つでよい。

2.データの追加、更新、削除などの考え方

データ追加、更新、削除の考え方が少し違います、
APIをコールするときのことを考えてください。

RESTfulAPIだと・・・

HTTPメソッドに応じてデータを追加したり、更新したりすると思います。

例えば、

students(生徒)のデータを操作したいときのことを考えます。

  • データを追加する場合は、HTTPメソッドのPOST
  • データを削除する場合は、HTTPメソッドのDELETE
    ほかにも、GET, PUT(PATCH) などを使用すると思います。

一方で、

GraphQLの場合・・・

二種類の操作(GraphQL QueryとGraphQL Mutation)を使うだけで良くなります。

subscripitonという操作も存在するのですが、今回は割愛します。

例えば

RESTfulAPIと同様に、students(生徒)のデータを操作したいときのことを考えます。

  • データを取得 したい場合は、GraphQL Queryを使用する
  • データを追加、更新、削除したい場合は、GraphQL Mutaionを使用する

このように2つだけ、取得、追加、更新、削除の処理を実行できます。

図にまとめるとこんな感じ

Restful API GraphQL
データの取得 GET Query
データの追加 POST Mutation
データの更新 UPDATE Mutation
データの削除 DELETE Mutation

じゃ、どう書けばいいんすか?

GraphQLでは2つ書くべきものがあります。

  1. GraphQLスキーマ(どういうデータを返すかを記載した仕様書のようなもの)
  2. GraphQLクエリ(こういうデータがほしいです、というのを記載したもの→APIのリクエストで使います)

graphQLではこのような記述をします。

今回はstudentsの情報を取得、更新するためのAPIを考えます。

まずはスキーマ

型やGraphQLの2つの操作を記載します。

graphQLスキーマ
type Query { #Queryは予約語→データ取得を行いたい処理を記載
  getStudents: [students] # Query名(引数):型
}
input Student {
  name: String!
  age: Int!
  grade: Int!
}
type Mutation { #Mutationも予約後→データ更新系を行いたい処理を記載
  createStudent(input: Student): students # Mutation名(引数:型):型
}

type students { # ←このように独自に型、objectを作る事も可能
  name: String!
  age: Int!
  grade: Int!
}

次にクエリ

実際にスキーマが完成したので、APIを実行してみましょう。
このような処理を記述します。

GraphQLクエリ
# <query or mutation> <任意の名前>
query getStudents {
  students { # 返り値の型を記載
    name # 取得したい値のみを選択
    age
  }
}

レスポンスとしては以下のとおり

{
  "data": {
    "students": [
      {
        "name": "一郎",
        "age": 20
      },
      {
        "name": "二郎",
        "age": 18
      },
    ]
  }
}

上の見ていただいたら、わかると思うのですが、APIを叩くときもjson構造のような指定の仕方をします。

GraphQLはなにがいいの?

上記を踏まえてまとめると以下のとおりです。

  • クライアントが好きな値のみを取得することができる。
    • RESTful APIはOverfetchingになりがち
      • studentの名前情報だけほしかったとしても,他の情報も取得してしまう
  • 直感的に記述できる
    • 上記の実行例を見てもらえばわかるようにほしい値をjson構造のような形で記載すればよいので、直感的
  • エンドポイントが増えすぎるのを防ぐことができる

じゃ、どうやってうごかすの?


実際に例としてgolangのgqlgenライブラリを利用して実装してみます。

必要ファイル

docker-compose.yml (中身はこちらをクリック
docker-compose.yml
version: "2"
services:
  sample:
    build: .
    tty: true
    volumes:
      - ./:/mnt
    ports:
      - 8081:8080
Dockerfile (中身はここをクリック
Dockerfile
FROM golang:alpine
WORKDIR /mnt
RUN go get -d -v golang.org/x/net/html
COPY . .

実行手順

コンテナ環境にログイン
# コンテナ環境を起動
$ docker-compose up -d
# コンテナ環境にログイン
$ docker-compose exec sample sh
GraphQLのスキーマの設計
schema.graphqls
type Query { #Queryは予約語→データ取得を行いたい処理を記載
  getStudents: [students] # Query名(引数):型
}
input Student {
  name: String!
  age: Int!
  grade: Int!
}
type Mutation { #Mutationも予約後→データ更新系を行いたい処理を記載
  createStudent(input: Student): students # Mutation名(引数:型):型
}

type students { # ←このように独自に型、objectを作る事も可能
  name: String!
  age: Int!
  grade: Int!
}
雛形ファイル作成
go run github.com/99designs/gqlgen init

上記コマンドを実行すると、自動的にひな形ファイルが生成されます、

処理追加

以下のファイルに処理を追加します

schema.resolver.go
func (r *mutationResolver) CreateStudent(ctx context.Context, input *model.Student) (*model.Students, error) {
	student := &model.Students{
		Name:  input.Name,
		Age:   input.Age,
		Grade: input.Grade,
	}
	r.students = append(r.students, student)
	return student, nil
}

func (r *queryResolver) GetStudents(ctx context.Context) ([]*model.Students, error) {
	return r.students, nil
}
graphqlサーバー起動&アクセス
#サーバー起動
$ go run server.go
2021/04/18 06:10:31 connect to http://localhost:8080/ for GraphQL playground

http://localhost:8081 にアクセスすると以下のような画面が表示される

この画面でgraphqlを試すことが可能です。

まとめ

  • GraphQLとは
    • 新しいAPI規格
    • データ取得にはQuery、データ更新系にはMutationを使う
  • GraphQLの特徴
    • エンドポイントが一つあればよい
    • 直感的に記述できる

最後に

graphqlについて簡単に解説してみました。
何かわからないこと、間違っていることなどがあればコメントお願いします。

参考

https://eh-career.com/engineerhub/entry/2018/12/26/103000
https://fullstackmark.com/post/17/building-a-graphql-api-with-aspnet-core-2-and-entity-framework-core