GraphQL で StarWars API の planets にネストされた films をとってくる
Tags: graphql, swapi
Published: 2022-06-25 15:56:39



## 何がしたいのか

Star Wars API を使って

GraphQL で複数のテーブルが関連したデータを取ってくる練習がしたかった。

appPlanets というエンドポイント？を叩いた。

https://www.back4app.com/database/davimacedo/swapi-star-wars-api/graphql-playground/all-planets

Chrome でアクセスするだけで実行できる
Back4App というところを使った。

https://github.com/graphql/swapi-graphql/blob/7c02fdf5244d8ca66005b9707f634b94364f31c1/schema.graphql#L483

定義はこの公式のスキーマの 483 行目から。

---

## Root -> allPlanets

```ts
type Root {
  allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection
  film(id: ID, filmID: ID): Film

  allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection
  planet(id: ID, planetID: ID): Planet

  node(
    """The ID of an object"""
    id: ID!
  ): Node
}
```

Root に AllPlanets が結び付けられている。
そしてそれが PlanetsConnection で Planet を参照しているようだ。

---

## PlannetsConnection -> Planet

```ts
type PlanetsConnection {
  totalCount: Int
  planets: [Planet]
}
```

PlannetsConnection の定義のコードを見ると
planets として Planet の配列が参照されている。

なので今回は planets をエンドポイントとして叩く。

---

## Planet

単体の Planet の定義もみてみる。

```ts
type Planet implements Node {
  """The name of this planet."""
  name: String
  gravity: String
  created: String
  id: ID!
}
```

* name
* gravity
* created
* id

これらの順番で中身が並べられている。

---

## Back4App で planets の GET を実行する

https://www.back4app.com/database/davimacedo/swapi-star-wars-api/graphql-playground/all-planets

Back4App なら Star Wars API の
リポジトリを clone して npm start しなくても
URL を開くだけで実行できる。

```ts
query allPlanets {
      planets (skip: 0, limit: 3) {
        results {
          id,
          name,
          gravity,
          createdAt,
        }
      }
    }
```

allPlanets という名前(ここは自由)で定義して
planets を叩く。

skip は 0 で最初のひとつめから、
limit は 3 で 3 つだけ

JS の関数の戻り値と似た感じで、
返す値は results で定義するようだ。

呼び出す順番は自由。

```ts
{
  "data": {
    "planets": {
      "results": [
        {
          "id": "JNgiSeuJwR",
          "name": "Yavin IV",
          "gravity": "1 standard",
          "createdAt": "2019-12-13T19:42:31.014Z"
        },
        {
          "id": "lZHyO0MIr6",
          "name": "Dagobah",
          "gravity": null,
          "createdAt": "2019-12-13T19:42:31.017Z"
        },
        {
          "id": "PL36fSGLoW",
          "name": "Tatooine",
          "gravity": "1 standard",
          "createdAt": "2019-12-13T19:42:30.901Z"
        }
      ]
    }
  }
}
```

結果は json で返ってくる。
data/tableName/results に入っている。

skip を 1 にすると
最初の Yavin IV が skip されて
Alderaan が 3 つめに食い込んでくる。

---

## filmConnection で Planet に結びつく Film も GET する

```ts
  filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection
```

Planet には Film とむすびつける
filmConnection というカラムもある。

これは PlanetFilmsConnection を使っていて

```ts
type PlanetFilmsConnection {
  pageInfo: PageInfo!
  totalCount: Int
  films: [Film]
```

このようになっている。

なので、films を追加すれば
惑星に関連するフィルムたちも取れるだろう。

```ts
type Film implements Node {
  title: String
  director: String
  releaseDate: String  
}
```

Film には
title, director, releaseDate,

これらの項目があったのでそれらをいれて 

```ts
query allPlanets {
      planets (skip: 0, limit: 3) {
        results {
          id,
          name,
          gravity,
          createdAt,
          films {
            results {
              title,
              director,
              releaseDate
            }
          }
        }
      }
    }
```

planets にリクエスト項目を追加する。

```json
          "createdAt": "2019-12-13T19:42:30.901Z",
          "films": {
            "results": [
              {
                "title": "A New Hope",
                "director": "George Lucas",
                "releaseDate": "1977-05-25T00:00:00.000Z"
              },
              {
                "title": "Attack of the Clones",
                "director": "George Lucas",
                "releaseDate": "2002-05-16T00:00:00.000Z"
              },
```

すると、films の項目で
惑星データに関連する映画のタイトル、監督、公開日、これらが取れた。

---

## まとめ

GraphQL をてっとり早く試すには

Back4App の Starwars API の
Planets と Films のデータが便利。

```ts
type Root {
  allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection
}
```

Root で allPlanets として PlanetsConnection
が結びついている。

なので allPanets というエンドポイントが発生すると推測する。

```ts
type PlanetsConnection {
  totalCount: Int
  planets: [Planet]
}
```

PlanetsConnection が planets として
Planet たちの配列を取っている。

```ts
type Planet implements Node {
  name: String
  id: ID!
}
```

そして Planet の内部に id や name などのカラムが入っている。

```ts
query allPlanets {
      planets (skip: 0, limit: 3) {
        results {
          id,
          name,
```

この形でリクエストする。results の中にカラムを書く。

```ts
  filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection
```

Planet の中にさらに filmConnection という
Planet と Films を結びつけるカラムがあり
PlanetFilmConnection を呼び出している

```ts
type PlanetFilmsConnection {
  pageInfo: PageInfo!
  totalCount: Int
  films: [Film]
```

PlanetFilmsConnection には films として
Film たちの配列が入っている。

これをリクエストするには、

```ts
query allPlanets {
      planets (skip: 0, limit: 3) {
        results {
          id,
          name
          films {
            results {
              title,
              director,
              releaseDate
            }
```

このように、results の films の更に results として
Film のカラムを書いてリクエストする。

以上。