GraphQL リゾルバの追加¶
Hono + GraphQL テンプレートは graphql-yoga を Hono の /graphql にマウントして同梱します。同じ URL に GraphiQL が含まれ、Drizzle/SQLite を背後に持つ users 型が用意されています。このレシピでは posts 型を追加して拡張します。
生成されるレイアウト¶
src/schema.graphql— 人間が編集する SDL (typeDefs にミラー)src/GraphqlSchema.res— yoga が消費するインライン化されたtypeDefsとrootValuesrc/Resolvers/Users.res— 既存の users クエリ/ミューテーションリゾルバsrc/Schema.res— Drizzle の users テーブルsrc/Server.res— yoga をマウントする Hono アプリ
Step 1 — SDL を拡張する¶
src/schema.graphql を編集して新しい型を追加します:
type Post {
id: Int!
title: String!
body: String!
}
extend type Query {
posts: [Post!]!
post(id: Int!): Post
}
extend type Mutation {
createPost(title: String!, body: String!): Post!
}
src/GraphqlSchema.res の typeDefs テンプレート文字列にも同じ変更を反映してください — yoga は起動時にこのインライン SDL を読み込みます。
Step 2 — Drizzle テーブルを追加する¶
src/Schema.res に以下を追加します:
let posts = sqliteTable("posts", {
"id": intCol("id", {"primaryKey": true, "autoIncrement": true}),
"title": textCol("title", {"notNull": true}),
"body": textCol("body", {"notNull": true}),
})
pnpm db:generate
pnpm db:migrate
Step 3 — リゾルバを書く¶
src/Resolvers/Posts.res を作成します:
let listPosts = async (_parent, _args, _ctx, _info) => {
await Db.db
->Db.select({
"id": Schema.posts["id"],
"title": Schema.posts["title"],
"body": Schema.posts["body"],
})
->Db.from(Schema.posts)
->Db.allAsync
}
let createPost = async (_parent, args, _ctx, _info) => {
let inserted =
await Db.db
->Db.insert(Schema.posts)
->Db.values({"title": args["title"], "body": args["body"]})
->Db.returning
inserted->Array.get(0)
}
Step 4 — rootValue に配線する¶
src/GraphqlSchema.res で:
let rootValue = {
"users": Resolvers.Users.listUsers,
"user": Resolvers.Users.userById,
"createUser": Resolvers.Users.createUser,
"deleteUser": Resolvers.Users.deleteUser,
"posts": Resolvers.Posts.listPosts,
"createPost": Resolvers.Posts.createPost,
}
Step 5 — 動作確認¶
pnpm dev
http://localhost:4000/graphql を開いて以下を実行します:
mutation {
createPost(title: "Hello", body: "World") { id title }
}
query { posts { id title body } }
Step 6 — ドキュメントを再生成する¶
pnpm docs:graphql
これは src/schema.graphql に対して graphql-markdown を実行し、docs/schema.md (kind でグループ化) を書き出します。ドキュメントがスキーマに追従するよう、このファイルをコミットしてください。
実運用リゾルバのパターン¶
フィールドレベルのリゾルバ — 投稿の著者解決を各クエリで再取得するのではなく、
Post.author内に配置するローダー —
Post.author呼び出しをバッチ化するにはdataloaderを使用し、@module("dataloader")でバインドするコンテキスト — 認証情報や DB ハンドルはモジュールレベルの
Db.dbではなく、yoga のcontextオプション経由で引き回す
よくある落とし穴¶
スキーマの乖離 —
src/schema.graphqlとインラインのtypeDefs文字列は一致していなければなりません。readFileSyncで単一ファイルを読み込めば回避できますが、起動時にファイルシステムアクセスが必要になります。テンプレートは自己完結性を保つためインライン化しています。ミューテーションが null を返す — Drizzle ビルダーで
returningが呼ばれているか確認してください。insert(...).values(...)だけでは行を返しません。