Speaking Report from "Cloudflare Workers Tech Talks in Fukuoka #1" ~ Decision-Making for Adopting Hono in Acsim, an AI Requirements Definition Platform
I had the opportunity to speak at the community event “Cloudflare Workers Tech Talks in Fukuoka #1” held in Fukuoka.
This article shares the content of the presentation along with the materials.
Below are excerpts from the presentation slides “Why We Chose Hono for Acsim” from the event.
I introduced the reasons for adopting Hono + @hono/zod-openapi in the development of Acsim, an AI requirements definition platform, and the development experience it brought.
Through schema-driven development utilizing OpenAPI, we achieved the following 👇
Improving implementation speed between Frontend and API
Quality improvement through sharing type information
API (Hono + @hono/zod-openapi)
↓
OpenAPI Schema Generation
↓
Frontend (orval)
↓
Type Information + TanStack Query Client Generation
const route = createRoute({
method: 'post',
path: '/users',
request: { body: { content: { 'application/json': { schema: UserSchema } } } },
responses: { 200: { content: { 'application/json': { schema: UserSchema } } } }
});// Auto-generated code
export const useGetUsers = () => {
return useQuery({
queryKey: ['users'],
queryFn: () => getUsersApi(),
});
};| Approach | Adopted | Reason |
|---|---|---|
| Generate both API/Frontend with orval | ❌ | Difficult to insert Middleware |
| openapi-generator | ❌ | Requires extensive configuration for TanStack Query integration |
| @hono/zod-openapi + orval | ✅ | Optimal learning cost and compatibility |
OpenAPI Schema needs to be updated when API changes
Cost of writing OpenAPI Schema
orval configuration cost
While type safety between frontend and API is guaranteed by type definitions, there was a problem with backend responses:
By parsing responses with Zod schema at runtime:
...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,
},
};
// Automatically apply response schema validation middleware
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();
// Validate only JSON responses with success status codes (200-299)
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) {
// Return 500 error on parse failure to detect issues immediately
c.res = c.json({ message: "Response schema validation failed", errors: result.error.flatten().fieldErrors }, 500);
return;
}
// Safely exclude extra properties using Zod's safeParse
c.res = c.json(result.data, status);
};
};Ensuring type safety at both compile-time and runtime:
This allows us to maximize the benefits of schema-driven development.
Thank you so much to everyone who attended, the Cloudflare team, yusukebe-san (the creator of Hono), and seike460-san for giving me the opportunity to speak!
The first Cloudflare Workers Tech Talks held in Fukuoka was incredibly stimulating, with presentations from other speakers, and I could feel the enthusiasm of the Cloudflare and Hono communities firsthand.
That’s all from the Gemba, where we continue to practice schema-driven development with Hono.