GraphQL

更新:2025-03-23
Query

概要

GraphQL」は、API向けクエリ言語。

プロジェクト

Node.jsのプロジェクトを作成。

/some/directory
npm init -y

ESMで記述したいので、typeを追記しておく。

/some/directory/package.json
{
..
"type": "module"
}

開発環境

モジュールの追加

/some/directory
npm i apollo-server graphql typescript @types/graphql @types/node
モジュール名簡易説明
apollo-serverGraphQLサーバー
graphqlGraphQL
typescriptTypeScript
@types/graphqlGraphQLの型
@types/nodeNode.jsの型
/some/directory
npm i -D @graphql-codegen/cli @graphql-codegen/typescript tsx
モジュール名簡易説明
@graphql-codegen/cliGraphQL Code GeneratorのCLI
@graphql-codegen/typescriptTypeScriptの型を生成するプラグイン
tsxTypeScriptファイルを実行するCLI

実装

スキーマの作成

スキーマは、APIのデータ構造を定義する役割。たとえば何かのモンスターに関するデータを用意してみる。

/some/directory/schema.ts
import { gql } from 'apollo-server';
const typeDefs = gql`
type Query {
monsters: [Monster!]!
}
type Monster {
id: ID!
name: String!
element: Element!
}
enum Element {
Fire
Water
Earth
Wind
Thunder
}
`;
export default typeDefs;

idはNumberStringでもいけるが、IDを指定することでユニークであることを表現できる。

型の生成

schema.tsからtypes.tsを生成する設定を用意。

/some/directory/codegen.yml
schema: "schema.ts"
generates:
types.ts:
plugins:
- "typescript"

GraphQL Code Generatorで生成。

/some/directory
npx graphql-codegen

以下のようなファイルが生成された。

/some/directory/types.ts
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: { input: string; output: string; }
String: { input: string; output: string; }
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
};
export enum Element {
Earth = 'Earth',
Fire = 'Fire',
Thunder = 'Thunder',
Water = 'Water',
Wind = 'Wind'
}
export type Monster = {
__typename?: 'Monster';
element: Element;
id: Scalars['ID']['output'];
name: Scalars['String']['output'];
};
export type Query = {
__typename?: 'Query';
monsters: Array<Monster>;
};

リゾルバーの作成

リゾルバーは、クエリに対してデータを返す役割。

/some/directory/resolvers.ts
import { IResolvers } from '@graphql-tools/utils';
// 生成した型が使えるので、自分でinterfaceを定義する必要がない
import { Monster, Element } from './types'
// 適当なモンスターデータを用意
const monsters: Monster[] = [
{
id: '001',
name: 'AAAAA',
element: Element.Fire
},
{
id: '002',
name: 'BBBBB',
element: Element.Water
},
{
id: '003',
name: 'CCCCC',
element: Element.Earth
},
{
id: '004',
name: 'DDDDD',
element: Element.Wind
},
{
id: '005',
name: 'EEEEE',
element: Element.Thunder
}
];
const resolvers: IResolvers = {
Query: {
monsters: (): Monster[] => monsters
}
};
export default resolvers;

サーバの作成

/some/directory/index.ts
import { ApolloServer } from 'apollo-server';
import typeDefs from './schema';
import resolvers from './resolvers';
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Local: ${url}`);
});

実行

/some/directory
npx tsx index
# http://localhost:4000/

「Query your server」でGUIにアクセスできるので、クエリを実行すればデータが取得できる。

Operation
query {
monsters {
name
}
}
Response
{
"data": {
"monsters": [
{
"name": "AAAAA"
},
{
"name": "BBBBB"
},
{
"name": "CCCCC"
},
{
"name": "DDDDD"
},
{
"name": "EEEEE"
}
]
}
}

続く...かもね