3
1

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 1 year has passed since last update.

【サーバーレスでGraphQL】AWS AppSyncのSchemaからcodegenする

Posted at

AWS AppSyncに生成したSchemaからcodegenする

はじめに

GraphQLやTypeScriptなど最近のフロントエンド開発は堅牢性を日々増していっているのを感じます。とくにRESTが抱えていた問題を一挙に解決する目的でつくられたGraphQLのエコシステムはこれまでにない開発体験を与えてくれます。

そんな便利なGraphQLですがAWSのAppSyncでは、それをサーバーレスで提供してくれます。サーバーレスでGraphQLを提供できるようなフレームワークはまだ多くないのでとてもいいですね。

ということでこの記事ではAppSyncで作ったAPIから出力されたスキーマを用いてフロントエンドで利用するコードを生成しようと思います。

環境

項目 バージョン
node 16.13.2
aws-cli 2.4.15
cdk 2.10.0

実装概要

AppSync

今回は純粋なAPIとしてのみ利用したいのでAmplifyを利用せず、AppSyncのみを作成します。
またIaCなどは利用せず、コンソール画面上からポチポチやっていきます。

Apollo Client React Hooks

スキーマ情報からGraphQL管理ライブラリであるApollo ClientのReact Hooksを生成します。
型補完などが動作するかも確認します。

実装

AppSync

画面でポチポチつくっていきます。
中身はなんでもいいのでイベントアプリというサンプルプロジェクトで開始します。
image.png

続けます。
image.png

いい感じに複雑そうなスキーマができました。
image.png

フロントのコード生成で利用するので設定 > API DetailsでAPI URL、API ID、API KEYをコピーしておきます。
Screen Shot 2022-02-03 at 21.29.38.png

Apollo Client React Hooks

craを利用してReactのテンプレートを作成します。

npx create-react-app apollo-codegen --template typescript
cd apollo-codegen
npm install graphql @apollo/client @graphql-codegen/cli @graphql-codegen/introspection @graphql-codegen/typescript @graphql-codegen/typescript-react-apollo @graphql-codegen/typescript-operations dotenv

コード生成用のプログラムを記述します。
下記のファイルでは、src/graphqlフォルダ下に記述したxxxx.gqlを読み込み、その型情報やhooksをsrc/generated/graphql.tsxに出力するようになっています。

.graphql.codegen.js
module.exports = {
  schema: [
    {
      [process.env.REACT_APP_GRAPHQL_API_URL]: {
        headers: { "X-API-KEY": process.env.REACT_APP_GRAPHQL_API_KEY },
      },
    },
  ],
  documents: ["./src/graphql/**.gql"],
  overwrite: true,
  generates: {
    "./src/generated/graphql.tsx": {
      plugins: [
        "typescript",
        "typescript-operations",
        "typescript-react-apollo",
      ],
      config: {
        skipTypename: false,
        withHooks: true,
        withHOC: false,
        withComponent: false,
      },
    },
    "./graphql.schema.json": {
      plugins: ["introspection"],
    },
  },
};

REACT_APP_GRAPHQL_API_URLREACT_APP_GRAPHQL_API_KEY.envに記述します。
AppSyncの設定画面からコピーします。(REACT_APP_とついているのは後のReactのプログラムでも流用するためです。)

REACT_APP_GRAPHQL_API_URL=https://xxxxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql
REACT_APP_GRAPHQL_API_KEY=xxxxxxxxxx

package.jsonのscriptsにqqlcodegenコマンドを追加します。

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "gqlcodegen": "graphql-codegen --require dotenv/config --config .graphql.codegen.js"
  },

最後にサンプルとして以下のGraphQLファイルを追加します。

src/graphql/query.graphql
query ListEvents {
  listEvents {
    items {
      id
      name
      description
      when
      where
    }
  }
}

コード生成

以下のコマンドでコードを生成してみます。

npm run gqlcodegen

> apollo-codegen@0.1.0 gqlcodegen
> graphql-codegen --require dotenv/config --config .graphql.codegen.js
  ✔ Parse configuration
  ✔ Parse configuration
  ✔ Generate outputs

src/generated/graphql.tsxを確認します。
image.png

hooksやその型情報が生成されていることがわかります。

動作確認

ApolloProviderを記述して

ApolloProvider.tsx
import React from "react";
import {
  ApolloClient,
  ApolloProvider as BaseApolloProvider,
  InMemoryCache,
} from "@apollo/client";

const client = new ApolloClient({
  uri: process.env.REACT_APP_GRAPHQL_API_URL!,
  // API_KEYをフロントで使うのは基本的にNGだがテスト的に使う
  headers: { "X-API-KEY": process.env.REACT_APP_GRAPHQL_API_KEY! },
  cache: new InMemoryCache(),
});

const ApolloProvider: React.FC = ({ children }) => {
  return <BaseApolloProvider client={client}>{children}</BaseApolloProvider>;
};

export default ApolloProvider;

index.tsxで呼び出して

index.tsx
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import ApolloProvider from "./ApolloProvider";

ReactDOM.render(
  <React.StrictMode>
    <ApolloProvider>
      <App />
    </ApolloProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

App.tsxでlistEventを呼び出してみます。

App.tsx
import React from "react";
import "./App.css";
import { useListEventsQuery } from "./generated/graphql";

function App() {
  const { data } = useListEventsQuery();

  return (
    <div className="App">
      <ol>
        {data?.listEvents?.items?.map((item) => {
          return (
            <li key={item?.id}>
              {item?.name} 場所:{item?.where} 日時:{item?.when}
            </li>
          );
        })}
      </ol>
    </div>
  );
}

export default App;

型補完もいい感じに効いてそうです。
image.png

DynamoDBに適当なデータをいれて
image.png

npm startすると
image.png

いい感じに動作してそうです。

最後に

AppSyncでもGraphQLの強力なエコシステムの恩恵を受けることができそうです。GraphQLは今後も積極的に採用していきたいですが、まだまだサーバーレスでの選択肢は多くないので有効な選択肢になると思います。
またAppSync自体の管理ですがServerless FrameworkAmplifyCDKなどさまざまあります。個人的にはAmplifyはGUIなどもあり、かなり強力ですが、猛烈にロックインする必要があるので少し躊躇するところでもあります。このあたりも知見をためていきたいです。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?