「Cloudflare Workers Tech Talks in Fukuoka #1」登壇レポート 〜 Honoを技術選定したAI要件定義プラットフォームAcsimでの意思決定
福岡で開催されたコミュニティイベント「Cloudflare Workers Tech Talks in Fukuoka #1」に登壇する機会をいただきました。
本記事では、当日の発表内容について、資料と共に共有します。
以下、当日の登壇資料 Honoを技術選定したAI要件定義プラットフォームAcsimでの意思決定 から一部抜粋します。
AI要件定義プラットフォーム Acsim の開発において、Hono + @hono/zod-openapi を採用した理由と、それがもたらした開発体験について紹介しました。
OpenAPIを活用したスキーマ駆動開発により以下を実現👇
Frontend・API間の実装速度の向上
型情報の共有による品質向上
API (Hono + @hono/zod-openapi)
↓
OpenAPI Schema 生成
↓
Frontend (orval)
↓
型情報 + TanStack Query Client 生成
const route = createRoute({
method: 'post',
path: '/users',
request: { body: { content: { 'application/json': { schema: UserSchema } } } },
responses: { 200: { content: { 'application/json': { schema: UserSchema } } } }
});// 自動生成されたコード
export const useGetUsers = () => {
return useQuery({
queryKey: ['users'],
queryFn: () => getUsersApi(),
});
};| 方式 | 採用 | 理由 |
|---|---|---|
| orvalでAPI/Frontend両方生成 | ❌ | Middlewareの差し込みが困難 |
| openapi-generator | ❌ | TanStack Queryとの連携で設定量が多い |
| @hono/zod-openapi + orval | ✅ | 学習コスト・親和性が最適 |
API変更時にOpenAPI Schemaの更新が必要
OpenAPI Schemaの記述コスト
orvalの設定コスト
フロントエンドとAPI間は型定義により型安全性が保証されているが、バックエンド側のレスポンスには問題がありました:
実行時にZodスキーマでレスポンスをパースすることで:
...createResponsesAndMiddleware({
response: {
schema: getAsIsPatternResponseSchema,
status: 200,
description: "asIsの業務パターンの詳細を取得します",
},
}),export const createResponsesAndMiddleware = <T extends z.ZodSchema, U extends ContentfulStatusCode>({
response,
middleware: _middleware = [],
}: {
response: { schema: T; status: U; description: string };
middleware?: MiddlewareHandler[];
}) => {
const { schema, status, description } = response;
const responses: { [key in U]: { content: { "application/json": { schema: T } }; description: string } } = {
[status]: {
content: {
"application/json": {
schema,
},
},
description,
},
};
// レスポンススキーマバリデーションミドルウェアを自動で適用
const middleware = [responseSchemaValidationMiddleware(schema, status), ..._middleware];
return { responses, middleware };
};export const responseSchemaValidationMiddleware = <T extends ZodSchema, U extends ContentfulStatusCode>(
schema: T,
status: U
): MiddlewareHandler => {
return async (c, next) => {
await next();
// 成功ステータスコード(200-299)のJSONレスポンスのみを検証
if (c.res.headers.get("Content-Type") !== "application/json") return;
if (!isSuccessStatusCode(c.res.status)) return;
const responseData = await c.res.json();
const result = schema.safeParse(responseData);
if (!result.success) {
// パース失敗時は500エラーを返し、問題を即座に検出
c.res = c.json({ message: "Response schema validation failed", errors: result.error.flatten().fieldErrors }, 500);
return;
}
// ZodのsafeParseにより余分なプロパティを安全に除外
c.res = c.json(result.data, status);
};
};型安全性をコンパイル時+実行時の両方で担保:
これにより、スキーマ駆動開発のメリットを最大限に活用できています。
当日ご参加いただいた皆様、Cloudflare社の皆様、そしてHonoの作者である yusukebe さん、登壇の機会をくださった seike460 さん、本当にありがとうございました!
福岡での初開催となったCloudflare Workers Tech Talksは、他の登壇者の方々の発表も非常に刺激的で、CloudflareやHonoコミュニティの熱量を肌で感じることができました。
以上、Honoでスキーマ駆動開発を実践していきたい、現場からお送りしました。