2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Apollo のチュートリアルをやったので、そこから分かったことをざっくりまとめ

時間がある人は Apollo がとても丁寧にチュートリアルを作ってるので、実際に手を動かしてやるととても理解が深まります
https://www.apollographql.com/docs/tutorial/introduction/

動機

GraphQL とはなんぞやということが知りたかった

概要

サーバーサイドでやること

GraphQL ではまず下記の三つを定義

  • スキーマ(js のオブジェクト go の構造体みたいなの)
  • Query(REST で言うとこの GET のメソッドたち)
  • Mutation(REST で言うとこの POST, PUT, DELETE のメソッドたち)

DB(データソース)へのコネクトの conf 書いて
Resolver(GET でどんな処理をするかとか POST でどんな処理するかとか)を定義する

クライアントサイドでやること

Apollo Client を使って GrapQL をかく
(他にもクライアントサイドでの state の管理とかできるけど今回は割愛)

詳細

サーバーサイド

※チュートリアルで使ってた ApolloServer(すなわち node)前提

まず GraphQL で扱うスキーマを定義

const { gql } = require("apollo-server");

const typeDefs = gql`
  type Anime {
    id: ID!
    title: String
    charactor: [Charactor]
  }

  type Charactor {
    id: ID!
    name: String
    age: String
    description: String
  }
`;

Query(REST でいうところの GET を定義)

type Queryの中に GET のメソッド書く感じ

const typeDefs = gql`
  # ↑のコードの続き

  type Query {
    animes: [Anime]
    anime(id: ID!): Anime
  }
`;

Mutation(REST でいうところの POST PUT DELETE を定義)

type Mutationの中にメソッド書く感じ
今回は Anime を delete するメソッドと Anime の title を更新するメソッドを追加

const typeDefs = gql`
  # ↑のコードの続き

  # mutation実行時用のschemaを作る
  type AnimeUpdateResponse {
    success: Boolean!
    message: String
    anime: [Anime]
  }

  type Mutation {
    deleteAnime(animeId: ID!): AnimeUpdateResponse
    updateTitle(animeId: ID!, title: string!): AnimeUpdateResponse
  }
`;
Query の resolver の定義

今回の場合、Query で定義した animes と anime メソッドの処理内容

module.exports = {
  Query: {
    animes: async (_, __, { dataSources }) =>
      await dataSources.animeAPI.getAllAnimes(),
    anime: async (_, { id }, { dataSources }) =>
      await dataSources.animeAPI.getAnimeById({ animeId: id }),
  },
};

dataSources.animeAPIが DB とのやり取りする adapter 的な感じ

こんな graphql がかけるようになる
GetAnimes は任意のクエリ名。

query GetAnimes {
  animes() {
    id
    title
    charactor {
      name
      description
    }
  }
}

これはこんな感じのレスポンスを返してくれる
(イメージです。現実には違うかもしれません)

{
  "data": {
    "animes": {
      "anime": [
        {
          "id": "1",
          "charactor": [
            {
              "name": "高須 竜児",
              "description": "目つきが悪い。家事がうまい。"
            },
            {
              "name": "逢坂 大河",
              "description": "元祖ツンデレ"
            }
          ]
        }
      ]
    }
  }
}

必要なカラムだけ指定すれば良きなの、とても便利ですよねぇ

Mutation の resolver の定義

今回の場合、anime の update と delete
面倒なので delete のみ

module.exports = {
  // Query: {
  // ...
  // },
  Mutation: {
    deleteAnime: async (_, { id }, { dataSources }) => {
      const result = await dataSources.animeAPI.delete({ id });
      // AnimeUpdateResponseに合わせる
      if (!result)
        return {
          success: false,
          message: "faild delete anime",
        };

      const animes = await dataSources.animeAPI.getAllAnimes();
      return {
        success: true,
        message: "success delete anime",
        animes,
      };
    },
  },
};

こんな graphql がかける

query DeleteAnimes {
  deleteAnime(id: 1) {
    success
    message
    animes {
      id
    }
  }
}

apollo server の起動

const { ApolloServer } = require("apollo-server");
const typeDefs = require("./schema");
const { createStore } = require("./utils");
const resolvers = require("./resolvers");

// DBのコネクト
const store = createStore();

// DBのadapter的な
const AnimeAPI = require("./datasources/anime");

const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => ({
    animeAPI: new AnimeAPI({ store }),
  }),
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

クライアントサイド

チュートリアルが React なので React で

ApolloClient の import

ApolloClient は ApolloProvider に渡す

import { ApolloClient } from "apollo-client";
import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import { ApolloProvider } from "@apollo/react-hooks";
import React from "react";
import ReactDOM from "react-dom";
import Pages from "./pages";

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: "http://localhost:4000/",
});

const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
  cache,
  link,
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <Pages />
  </ApolloProvider>,
  document.getElementById("root")
);

GraphQL の実行

hooks(useQuery, useMutation) を使って grapql 実行する

import React from "react";
import { useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";

export const GET_ANIMES = gql`
  query GetAnimes {
    animes() {
      id
      title
      charactor {
        name
        description
      }
    }
  }
`;

export const Animes: React.FC = () => {
  // GET_ANIMESで定義したqueryを実行する
  // <GetAnimes>はdataの型(apolloで自動生成される)
  const { data } = useQuery<GetAnimes>(GET_ANIMES);

  return (
    <Div>
      {data.animes.map((anime) => (
        <AnimeList title={anime.title} />
      ))}
    </Div>
  );
};

所感

大元のスキーマや Query、Mutation さえサーバサイド側で決めとけば
あとはよしなにクライアントサイド側で好きなスキーマで Query や Mutation かけるのは便利ぃ

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?