なにこれ
「とりあえずクライアント側と同じJavaScriptで手っ取り早くGraphQLサーバー立てたい!」
このようなユースケースにGraphpackはピッタリです。
設定いらずのNode製GraphQLサーバーで 「GraphQLのスキーマとリゾルバーを定義するだけでOK」、さらに **「GraphQL Playground IDEが標準搭載」**なのでクライアント側を自前で実装せずとも動作確認できます。
今回は、このGraphpackの使い方について以下の5ステップでご紹介します。
※ここで紹介するソースコードはGitHub(Takumon/nuxt-graphpack-sample)にもあるので参考にしてみてください。
- 🔰 Graphpackとは
- 💪 Graphpackを使ってみる
- 💖 GraphpackでQueryを実装・動作確認する
- ✨️ GraphpackでMutationを実装・動作確認する
- 💎 GraphpackでSubscriptionを実装・動作確認する
1. Graphpackとは
Node.js製のゼロコンフィグなミニマルGraphQLサーバーでWebpack、Nodemon、Apollo Server をイイ感じにまとめたライブラリです。感触を掴むだけならCodeSandboxのお試し環境が用意されているので、そちらを触ってみるとよいでしょう。 READMEでは以下8つの特徴をうたっています。
- 📦 設定いらず(ZERO-CONFIG)!
- 🚦 ライブリロード機能組み込み済!
- 🚨 わかりやすいエラーメッセージ!
- 🎮 GraphQL Playground IDE 標準装備!
- ⭐️ SDLでスキーマ定義可能(GraphQL imports)
- 💖 TypeScriptをサポート
- 🔥 爆速ビルド
- ⚡️ ES module importsとdynamic importをサポート
2. Graphpackを使ってみる
実装してみる
- プロジェクト雛形を作成し、
graphpack
を開発環境用ライブラリとしてインストールします。
mkdir graphpack-sample
cd graphpack-sample
npm init
npm i -D graphpack
src/schema.graphql
とsrc/resolver.js
を作成します。
graphpack-sample
└── src
├── resolvers.js
└── schema.graphql
type Query {
hello: String
}
const resolvers = {
Query: {
hello: () => 'world!',
},
};
export default resolvers;
package.json
に以下のスクリプトを追記します。
"scripts": {
"dev": "graphpack",
"build": "graphpack build"
},
動作確認してみる
- サーバーを
npm run dev
で起動して、ブラウザでhttp://localhost:4000/
を開くとGraphQL Playground IDEが表示されます。
- 試しに以下のQueryを実行してみましょう。
query {
hello
}
world!
がレスポンスとして返ってきます。
こんな感じで、とても簡単にGraphQLサーバーが立てられます。
3. GraphpackでQueryを実装・動作確認する
ユーザー情報(ID、名前、メール、年齢)を扱う処理を例に実装方法を説明します。
実装
- ユーザー情報のスキーマ定義します。
type Query {
users: [User!]!
user(id: ID!): User!
}
type User {
id: ID!
name: String!
email: String!
age: Int
}
- 仮のユーザー情報を用意しましょう。
export let users = [
{
id: 1,
name: 'gatsby taro',
email: 'gatsby.taro@gmail.com',
age: 32
},
{
id: 2,
name: 'gridsome taro',
email: 'gridsom.taro@gmail.com',
age: 55
},
];
- 最後にリゾルバーを定義します。データは前手順で作成したものを使います。
import { users } from './db';
const resolvers = {
Query: {
// 1件検索
user: (parent, { id }, context, info) => users.find(user => user.id == id),
// 複数件検索(簡単のため全件検索としている)
users: (parent, args, context, info) => users
},
};
動作確認
- 実装できたら
npm run dev
でサーバー起動してhttp://localhost:4000/
を開いて
以下のクエリを発行します。するとユーザー一覧が取得できます。
query {
users {
id
name
email
age
}
}
- 1件検索の場合は以下のようなクエリを発行しましょう。指定したIDのユーザー情報が取得できます。
query {
user(id: 1) {
id
name
email
age
}
}
4. GraphpackでMutationを実装・動作確認する
ユーザー情報が取得できたので、次はユーザー情報の登録・更新・削除を実装します。
実装
スキーマ定義にMutationを追記します。
type Mutation {
// 登録
createUser(
name: String!,
email: String!,
age: Int
): User!
// 更新
updateUser(
id: ID!,
name: String!,
email: String,
age: Int
): User!
// 削除
deleteUser(
id: ID!
): User!
}
これはGraphQLとは関係ありませんが、ユーザー情報登録時のID採番用ロジックをdb.js
に追記します。
初期状態でユーザー情報が2件なので、採番用IDは3から始まるようにします。
export let users = [
{
id: 1,
name: 'gatsby taro',
email: 'gatsby.taro@gmail.com',
age: 32
},
{
id: 2,
name: 'gridsome taro',
email: 'gridsome.taro@gmail.com',
age: 55
},
];
// 採番用ID(3から始まるようにする)let idSequence = 2;// 採番処理export const generateId = () => ++idSequence;
リゾルバーにMutationを追記します。
import { users, generateId } from './db';
const resolvers = {
Query: {
// ・・・
},
Mutation: { createUser: (parent, { name, email, age }, context, info) => { const newUser = { id: generateId(), name, email, age}; users.push(newUser); return newUser; }, updateUser: (parent, { id, name, email, age }, context, info) => { const updatedUser = users.find(user => user.id == id); updatedUser.name = name; updatedUser.email = email; updatedUser.age = age; return updatedUser; }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id == id); if (userIndex === -1) throw new Error('User not found'); const [deletedUser] = users.splice(userIndex, 1); return deletedUser; } }, // ・・・
};
動作確認
実装できたらnpm run dev
でサーバー起動して http://localhost:4000/
を開きます。
登録の動作確認
以下のようなMutationを発行すると、登録したユーザー情報が返ってきます。
※登録後にユーザー一覧を取得すると、nuxt taro
が取得できます。
mutation {
createUser(
name: "nuxt taro"
email: "nuxt.taro@gmail.com"
age: 43
) {
id
name
email
age
}
}
更新の動作確認
今度はnuxt taro
を更新してみましょう。
以下のようなMutationを発行すると、更新されたユーザー情報が返ってきます。
※更新後にユーザー一覧を取得するとnuxt taro
がnuxt updatedtaro
になっていることを確認できます。
mutation {
updateUser(
id: 3
name: "nuxt updatedtaro"
email: "nuxt.updatedtaro@gmail.com"
age: 44
) {
id
name
email
age
}
}
削除の動作確認
最後にnuxt updatedtaro
を削除してみましょう。
以下のようなMutationを発行すると削除されたユーザー情報が返ってきます。
※削除後にユーザー一覧を取得するとnuxt updatedtaro
がなくなっていることが確認できます。
mutation {
deleteUser(
id: 3
) {
id
name
email
age
}
}
5. GraphpackでSubscriptionを実装・動作確認する
実装
GraphpackではSubscriptionはデフォルトoffになっています。
そのためココだけは設定ファイルを作成する必要があります。
プロジェクトのルートフォルダ直下にgraphpack.config.js
を作成しましょう。
module.exports = {
server: {
subscriptions: {
// Subscriptionのエンドポイントとして
// QueryとMutationと同じパスを設定します。
path: `/graphql`
}
},
};
スキーマ定義にSubscriptionを追記します。
type Subscription {
userCreated: User!
userUpdated: User!
userDeleted: User!
}
リゾルバーでSubscriptionを定義し、Mutationも修正します。 Mutationも修正するのは、登録・更新・削除完了後にSubscriptionを発行できるようにするためです。
// Subscriptionのやりとりには`apollo-server`のPubSubを使る// `graphpack`の場合、`apollo-server`は入っているimport { PubSub } from 'apollo-server';import { users, generateId } from './db';
const pubsub = new PubSub();
const EVENT = { USER_CRAETED: 'userCreated', USER_UPDATED: 'userUpdated', USER_DELETED: 'userDeleted',};
const resolvers = {
// ・・・
Mutation: {
createUser: (parent, { name, email, age }, context, info) => {
const newUser = { id: generateId(), name, email, age};
users.push(newUser);
pubsub.publish(EVENT.USER_CRAETED, {[EVENT.USER_CRAETED]: newUser}); return newUser;
},
updateUser: (parent, { id, name, email, age }, context, info) => {
const updatedUser = users.find(user => user.id == id);
updatedUser.name = name;
updatedUser.email = email;
updatedUser.age = age;
pubsub.publish(EVENT.USER_UPDATED, {[EVENT.USER_UPDATED]: updatedUser}); return updatedUser;
},
deleteUser: (parent, { id }, context, info) => {
const userIndex = users.findIndex(user => user.id == id);
if (userIndex === -1) throw new Error('User not found');
const [deletedUser] = users.splice(userIndex, 1);
pubsub.publish(EVENT.USER_DELETED, {[EVENT.USER_DELETED]: deletedUser}); return deletedUser;
}
},
Subscription: { [EVENT.USER_CRAETED]: { subscribe: () => pubsub.asyncIterator([EVENT.USER_CRAETED]) }, [EVENT.USER_UPDATED]: { subscribe: () => pubsub.asyncIterator([EVENT.USER_UPDATED]) }, [EVENT.USER_DELETED]: { subscribe: () => pubsub.asyncIterator([EVENT.USER_DELETED]) }, }, // ・・・
};
動作確認
実装できたらnpm run dev
でサーバー起動して http://localhost:4000/
を開きます。
userCreated
の動作確認をしましょう。
以下のようなSubscriptionを発行します。
subscription {
userCreated {
id
name
email
age
}
}
すると実行結果(画面右半分)にローディングアイコンが表示され、監視状態となります。
この状態で別タブを開き...
登録用のMutaitonを発行してみましょう。
これで、元のタブに戻ると、登録された情報がレスポンスで返ってきていれば成功です。
以上でSubscriptionの動作確認は終了です。 今回は紹介しませんが、userUpdatedとuserDeletedも同様の方法で動作確認できるのでやってみてください。
まとめ
今回はNode製GraphQLサーバー「Graphpack」の使い方について紹介しました。 上記で紹介した通り非常に簡単ですので、「とりあえずGraphQLサーバーを立ててみたい!」という方はGraphpackを検討してみてはいかがでしょうか🍅
参考
- A Beginner’s Guide to GraphQL - DEV Community 👩💻👨💻
- GraphpackでQuery、Mutationの実装方法を紹介している記事です。
- Logo design for Graphpack | Steemit
- Gpraphpackロゴ作成の舞台裏です。