はじめに
この記事は express-graphql
でNode.js
+ TypeScript
で簡単にGraphQL APIサーバを実装する
ハンズオンちっくな記事です。
実際に手を動かしてみてください🙏
ディレクトリ構造は下記のようになります。
.
├── src
│ ├── data
│ │ └── index.ts
│ ├── fields
│ │ ├── index.ts
│ │ └── member
│ │ ├── index.ts
│ │ ├── query.ts
│ │ ├── mutation.ts
│ │ ├── resolvers.ts
│ │ └── types.ts
│ └── index.ts
├── package.json
└── tsconfig.json
準備
パッケージのインストール
実行は ts-node
で行います。
yarn add @types/express cors express express-graphql graphql typescript
yarn add -D ts-node tsconfig-paths
tsconfig.json
alias
の登録をします。
{
"compilerOptions": {
"sourceMap": false,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"lib": ["es2018", "dom"],
"moduleResolution": "node",
"removeComments": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"strictFunctionTypes": false,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"],
}
},
"include": [
"./src/**/*.ts"
]
}
GraphQL Query
メンバー一覧を取得するAPI を実装します。
実装
Data
実際にこのDataは SQL
などからDBの値を取得しますが、今回は DB との接続はなしで JS
で用意します。
export const memberList = [
{
id: 1,
name: 'Rachel',
age: 29
},
{
id: 2,
name: 'Ross',
age: 29
},
{
id: 3,
name: 'Joey',
age: 29
}
];
Types
型定義を types.ts
として作成します。
import { GraphQLObjectType, GraphQLNonNull, GraphQLString, GraphQLInt } from 'graphql';
export const memberType = new GraphQLObjectType({
name: 'member',
description: 'member',
fields: {
id: {
type: new GraphQLNonNull(GraphQLInt),
description: 'The Member ID.'
},
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'The Member name.'
},
age: {
type: new GraphQLNonNull(GraphQLInt),
description: 'The Member age.'
}
}
});
Resolvers
Resolver
では何をレスポンスするかの処理を書きます。
この例ではメンバーリストを取得したいだけなので、そのまま memberList
を返します。
import { memberList } from '@/data';
export const getMemberList = () => Promise.resolve(memberList);
Query
Query
は REST APIの GET
に相当します。
import { GraphQLList } from 'graphql';
import { getMemberList } from '@/fields/member/resolvers';
import { memberType } from '@/fields/member/types';
export const memberQuery = {
memberList: {
type: new GraphQLList(memberType),
description: 'Get list of members data.',
resolve: getMemberList
}
};
src/fieles/member/index.ts
実装した member
モジュールの query
をまとめてエクスポートします。
import { memberQuery as query } from '@/fields/member/query';
export const memberField = {
query
};
src/fields/index
実装したすべてのモジュールを Root Query
としてまとめてエクスポートします。
import { GraphQLObjectType } from 'graphql';
import { memberField } from '@/fields/member/';
export const queryType = new GraphQLObjectType({
name: 'Query',
description: 'The root query type.',
fields: {
...memberField.query
}
});
Express
最後に Express
でサーバを実装します。
import * as express from 'express';
import * as graphqlHTTP from 'express-graphql';
import { GraphQLSchema } from 'graphql';
import { queryType } from '@/fields/';
const PORT = 4000;
const app = express();
const schema = new GraphQLSchema({
query: queryType
});
app.use(
'/graphql',
express.json(),
graphqlHTTP({
schema,
graphiql: true
})
);
app.listen(PORT, () => console.log('Listening on :4000'));
実行
サーバ起動
下記コマンドでAPIサーバを起動します。
yarn ts-node -r tsconfig-paths/register src/index.ts
動作チェック
localhost:4000/graphql
にアクセスすると、GraphiQL エディタが起動します。
下記クエリを入力して実行。memberList
が取得できれば成功🎉
query getMemberList {
memberList {
id
name
age
}
}
GraphQL Mutation
続いて Mutation
を実装します。
この例では新メンバーを追加する Mutation
を実装します。
実装
Types
入力側のパラメータの型を追加します。
export const memberCreateInput = new GraphQLInputObjectType({
name: 'memberCreateInput',
fields: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'The Member name.'
},
age: {
type: new GraphQLNonNull(GraphQLInt),
description: 'The Member age.'
}
}
});
Resolvers
新メンバーを追加する処理を追加します。
export const createMember = ({ name, age }: { name: string; age: number }) => {
const member = {
id: memberList.length + 1,
name,
age
};
memberList.push(member);
return memberList;
};
Mutation
新たに Mutation
を作成します。
import { GraphQLNonNull, GraphQLList } from 'graphql';
import { createMember } from '@/fields/member/resolvers';
import { memberType, memberCreateInput } from '@/fields/member/types';
export const memberMutation = {
createMember: {
type: new GraphQLList(memberType),
args: {
member: {
type: new GraphQLNonNull(memberCreateInput)
}
},
resolve: (_: any, args: any) => {
return createMember(args.member);
}
}
};
src/fieles/member/index.ts
実装した member の Mutation
をエクスポートします。
import { memberQuery as query } from '@/fields/member/query';
import { memberMutation as mutation } from '@/fields/member/mutation';
export const memberField = {
query,
mutation
};
src/fields/index
実装したすべてのモジュールを Root Mutation としてまとめてエクスポートします。
import { GraphQLObjectType } from 'graphql';
import { memberField } from '@/fields/member/';
export const queryType = new GraphQLObjectType({
name: 'Query',
description: 'The root query type.',
fields: {
...memberField.query
}
});
export const mutationType = new GraphQLObjectType({
name: 'Mutation',
description: 'The root Mutation type.',
fields: {
...memberField.mutation
}
});
Express
最後に Schema
に Mutation
を追加します。
import { queryType, mutationType } from '@/fields/';
const schema = new GraphQLSchema({
query: queryType,
mutation: mutationType
});
実行
サーバ起動
下記コマンドでAPIサーバを起動します。
yarn ts-node -r tsconfig-paths/register src/index.ts
動作チェック
下記クエリを入力して実行。memberList
に入力したメンバーが追加できれば成功🎉
mutation createMember {
createMember(member: {
name: "Monica"
age: 29
}) {
id
name
age
}
}
さいごに
GraphQL
のメリットとして、書いたコードがそのままドキュメントになることが挙げられます。
予め description
を書くルールなどを定めておけばAPI ドキュメントを用意する必要がなくなります。
実際に手を動かして、GraphQL
を体験してみてください!!!
以上