GraphQLについて少し調べた

# GraphQL用語

## Schema

- APIのこと。
- クライアントがサーバーにクエリを送信した時に、返却値として期待されるオブジェクトの型定義。
    - `type` キーワードによってGraphQLオブジェクトの型を定義する(その集合がSchema）。
    - 以下の例において、 `id`, `text`, `done`, `user`, `createTodo` などを field（フィールド） と呼ぶ。

```graphql
# 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!
}
```

https://gqlgen.com/getting-started/


## Resolver

- フィールド（`CreateTodo`, etc）の実装。
- クライアントが要求したフィールドの値を返却するための関数。
    - フィールドをresolve（解決する）ので `resolver`。

```go
// 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` が定義されている。

```graphql
query findTodos {
  todos {
    text
    done
    user {
      name
    }
  }
}
```

queryのレスポンス

```json
{
  "data": {
    "todos": [
      {
        "text": "todo",
        "done": false,
        "user": {
          "name": "user 1"
        }
      }
    ]
  }
}
```

### Mutation
- データの作成・更新・削除を行う言語。
- HTTP POST/PUT/DELETEに相当。

```graphql
mutation createTodo {
  createTodo(input: { text: "todo", userId: "1" }) {
    user {
      id
    }
    text
    done
  }
}
```

mutationのレスポンス

```json
{
  "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 | なし<br>(WebSocketを使う場合が多い) |  クエリ(subscription) |
| サーバの記述 |  ルーティングとコントローラ |  スキーマ(schema・type) / リゾルバ(resolver)<br><br>（エンドポイントは１つになるためルーティングの定義は最初の一回を除いて不要（なはず）） |

# REST API運用の課題

- サーバーサイドでユースケース毎にAPIが増える。
- クライアントサイドでドメインロジックを作ったり、状態を持つ必要性が出る。

# GraphQLのメリット

- クライアントサイドとサーバーサイドのコミュニケーションコストの削減。
    - グラフ構造でリレーションを表現できるので、サーバーサイドはユースケース毎のAPIを作る必要がなくなり、クライアントサイドでそのまま表示できるようなクエリを作れば良い。（？）
    - クライアントサイドは利用可能な全ての状態がわかり、必要なデータを選択できる。
- GraphQLクライアント(Appolo、Relayなど)を利用すると、グラフ構造をキャッシュしてくれる。これにより、
    - クライアントサイドは状態を持つ必要がなくなる。

# GraphQLのデメリット

- クエリのパフォーマンス問題や脆弱性を生みやすい。
[Securing Your GraphQL API from Malicious Queries](https://www.apollographql.com/blog/graphql/security/securing-your-graphql-api-from-malicious-queries/)

# よくある誤解

Q. DB構造をクライアントにそのまま公開してしまうのでは？
A. Hasuraを使った場合、DB構造からGraphQLスキーマを自動生成するが、これはRESTでも同様。

# 参照

https://qiita.com/saboyutaka/items/171f7382cdf75b67d076

https://zenn.dev/saboyutaka/articles/07f1351a6b0049

https://speakerdeck.com/sonatard/rethinking-graphql

https://speakerdeck.com/sonatard/graphql-knowhow

https://speakerdeck.com/sonatard/swiftui-graphql

https://note.com/konpyu/n/nc4fd122644a1

https://speakerdeck.com/qsona/architecture-decision-for-the-next-n-years-at-studysapuri

https://numb86-tech.hatenablog.com/entry/2022/03/14/203723

https://developer.ntt.com/ja/blog/878bdd00-c689-4fde-8473-fa93e8a96ba7

https://findy-code.io/pick-up/interviews/caddi-engineer

https://zenn.dev/eringiv3/books/a85174531fd56a

https://www.apollographql.com/docs/apollo-server

https://qiita.com/NagaokaKenichi/items/2770b151e86fb65ea11d

https://qiita.com/shotashimura/items/3f9e04b93e79592030a4

https://www.wantedly.com/companies/visitsworks/post_articles/327794

https://zenn.dev/nameless_sn/articles/graphql_tutorial