stoke the flame 🤙🔥
Utilities for hono and @hono/zod-openapi.
To see real world usage of these utilities, checkout the hono-open-api-starter routes example
- stoker
- Utilities
- Middlewares
- Open API
- Credits
HTTP status code constants. Provides individual typed / documented exports. Use anywhere you need a status code instead of hard coding raw numbers.
Sourced from http-status-codes | RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), RFC2518 (WebDAV), RFC6585 (Additional HTTP Status Codes), and RFC7538 (Permanent Redirect).
Why not use the
http-status-codes
package directly?http-status-codes
exports enums which do not work well with the@hono/zod-openapi
type system and the built inStatusCode
type fromhono/utils/http-status
.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
const app = new OpenAPIHono();
app.notFound((c) => {
return c.json({
message: `Not Found - ${c.req.path}`,
}, HttpStatusCodes.NOT_FOUND);
});
app.onError((err, c) => {
return c.json(
{
message: err.message,
},
HttpStatusCodes.INTERNAL_SERVER_ERROR,
);
});
app.openapi(
createRoute({
path: "/",
tags: ["Index"],
description: "Index route",
method: "get",
responses: {
[HttpStatusCodes.OK]: {
content: {
"application/json": {
schema: z.object({
message: z.string(),
}),
},
},
description: "Index route",
},
},
}),
(c) => {
return c.json({ message: "Hello World" }, HttpStatusCodes.OK);
},
);
export default app;
HTTP status phrase constants.
import * as HttpStatusPhrases from "stoker/http-status-phrases";
console.log(HttpStatusPhrases.NOT_FOUND); // Not Found
A default 404 handler.
- Responds with JSON object
- Message property includes not found path
- Sets status code to 404
import { Hono } from "hono";
import notFound from "stoker/middlewares/not-found";
const app = new Hono();
app.notFound(notFound);
export default app;
A default error handler.
- Responds with JSON object
- Message property includes error message
- Stack trace included when NODE_ENV !== "production"
- Sets status code to existing status code if already set OR 500
import { Hono } from "hono";
import onError from "stoker/middlewares/on-error";
const app = new Hono();
app.onError(onError);
export default app;
Serve an svg emoji as a favicon from /favicon.ico
import { Hono } from "hono";
import serveEmojiFavicon from "stoker/middlewares/serve-emoji-favicon";
const app = new Hono();
app.use(serveEmojiFavicon("🔥"));
export default app;
A default error hook you can include in your OpenAPIHono instance. Includes the success
status and ZodError
import { OpenAPIHono } from "@hono/zod-openapi";
import defaultHook from "stoker/openapi/default-hook";
/*
Any validation errors will respond with status code 422 and body:
{
success: false,
error: {}, // Full Zod Error
}
*/
const app = new OpenAPIHono({
defaultHook,
});
export default app;
Create a content / schema description with a type of application/json
import { z } from "@hono/zod-openapi";
import jsonContent from "stoker/openapi/helpers/json-content";
const schema = z.object({
message: z.string(),
});
/*
* Equivalent to:
{
content: {
"application/json": {
schema,
},
},
description: "Retrieve the user",
}
*/
const response = jsonContent(
schema,
"Retrieve the message"
);
Useful for json body schema validators.
Create a content / schema description with a type of application/json
and required set to true
import { z } from "@hono/zod-openapi";
import jsonContentRequired from "stoker/openapi/helpers/json-content-required";
const schema = z.object({
message: z.string(),
});
/*
* Equivalent to:
{
content: {
"application/json": {
schema,
},
},
description: "Retrieve the user",
required: true
}
*/
const response = jsonContentRequired(
schema,
"Retrieve the message"
);
Peer dependency of
@asteasolutions/zod-to-openapi
WARNING: Not recommended right now, type hints from @hono/zod-openapi are not correct when using this helper. If you don't absolutely need
oneOf
in your specification, use zodor
(anyOf) instead.
Create a json content / schema description where the schema can be oneOf multiple schemas. Useful when you have multiple possible validation response schemas.
import { z } from "@hono/zod-openapi";
import jsonContentOneOf from "stoker/openapi/helpers/json-content-one-of";
import createErrorSchema from "stoker/openapi/schemas/create-error-schema";
import IdParamsSchema from "stoker/openapi/schemas/id-params";
const bodySchema = z.object({
name: z.string(),
});
/*
* Equivalent to:
{
content: {
"application/json": {
schema: {
oneOf: SchemaObject[]
},
},
},
description: "Invalid Id params or Invalid Body"
}
*/
const result = jsonContentOneOf(
[createErrorSchema(IdParamsSchema), createErrorSchema(bodySchema)],
"Invalid Id params or Invalid Body"
);
Peer dependency of
@asteasolutions/zod-to-openapi
Used internally by stoker/openapi/helpers/json-content-one-of
but exported here in case you need to access the generated schemas for other use cases.
import { z } from "@hono/zod-openapi";
import oneOf from "stoker/openapi/helpers/one-of";
import createErrorSchema from "stoker/openapi/schemas/create-error-schema";
import IdParamsSchema from "stoker/openapi/schemas/id-params";
const bodySchema = z.object({
name: z.string(),
});
/*
* Returns: SchemaObject[]
*/
const result = oneOf([createErrorSchema(IdParamsSchema), createErrorSchema(bodySchema)]);
Commonly used zod schemas for use when creating routes with @hono/zod-openapi
Validate id
in path params as a number.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import jsonContent from "stoker/openapi/helpers/json-content";
import IdParamsSchema from "stoker/openapi/schemas/id-params";
const app = new OpenAPIHono();
app.openapi(
createRoute({
method: "get",
path: "/users/{id}",
request: {
params: IdParamsSchema,
},
responses: {
[HttpStatusCodes.OK]: jsonContent(
z.object({
id: z.number(),
}),
"Retrieve the user",
),
},
}),
(c) => {
// id is a valid number
const { id } = c.req.valid("param");
return c.json({
id,
}, HttpStatusCodes.OK);
},
);
export default app;
Validate slug
in path params as a slug.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import jsonContent from "stoker/openapi/helpers/json-content";
import SlugParamsSchema from "stoker/openapi/schemas/slug-params";
const app = new OpenAPIHono();
app.openapi(
createRoute({
method: "get",
path: "/posts/{slug}",
request: {
params: SlugParamsSchema,
},
responses: {
[HttpStatusCodes.OK]: jsonContent(
z.object({
slug: z.string(),
}),
"Retrieve the post",
),
},
}),
(c) => {
// slug is a valid slug
const { slug } = c.req.valid("param");
return c.json({
slug,
}, HttpStatusCodes.OK);
},
);
export default app;
Validate id
in path params as a uuid.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import jsonContent from "stoker/openapi/helpers/json-content";
import IdUUIDParamsSchema from "stoker/openapi/schemas/id-uuid-params";
const app = new OpenAPIHono();
app.openapi(
createRoute({
method: "get",
path: "/users/{id}",
request: {
params: IdUUIDParamsSchema,
},
responses: {
[HttpStatusCodes.OK]: jsonContent(
z.object({
id: z.uuid(),
}),
"Retrieve the user",
),
},
}),
(c) => {
// id is a valid uuid
const { id } = c.req.valid("param");
return c.json({
id,
}, HttpStatusCodes.OK);
},
);
export default app;
Validate a custom named path param using Zod string validators by calling the function getParamsSchema({ name, validator })
.
Name defaults to id
.
Validator defaults to uuid
and supports type "uuid" | "nanoid" | "cuid" | "cuid2" | "ulid"
.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import jsonContent from "stoker/openapi/helpers/json-content";
import getParamsSchema from "stoker/openapi/schemas/get-params-schema";
const app = new OpenAPIHono();
app.openapi(
createRoute({
method: "get",
path: "/users/{userId}",
request: {
params: getParamsSchema({
name: "userId",
validator: "nanoid",
}),
},
responses: {
[HttpStatusCodes.OK]: jsonContent(
z.object({
userId: z.nanoid(),
}),
"Retrieve the user",
),
},
}),
(c) => {
// userId is a valid nanoid
const { userId } = c.req.valid("param");
return c.json({
userId,
}, HttpStatusCodes.OK);
},
);
export default app;
Create an object schema with a message string property. Useful for error messages.
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import * as HttpStatusPhrases from "stoker/http-status-phrases";
import jsonContent from "stoker/openapi/helpers/json-content";
import createMessageObjectSchema from "stoker/openapi/schemas/create-message-object";
import IdParamsSchema from "stoker/openapi/schemas/id-params";
const app = new OpenAPIHono();
app.openapi(
createRoute({
method: "get",
path: "/some-thing-that-might-not-be-found",
responses: {
[HttpStatusCodes.NOT_FOUND]: jsonContent(
createMessageObjectSchema(HttpStatusPhrases.NOT_FOUND),
HttpStatusPhrases.NOT_FOUND,
),
},
}),
(c) => {
return c.json({
message: HttpStatusPhrases.NOT_FOUND,
}, HttpStatusCodes.NOT_FOUND);
},
);
export default app;
Create an example error schema with zod error / validation messages based on given schema.
import { createRoute, z } from "@hono/zod-openapi";
import * as HttpStatusCodes from "stoker/http-status-codes";
import jsonContent from "stoker/openapi/helpers/json-content";
import createErrorSchema from "stoker/openapi/schemas/create-error-schema";
const TaskSchema = z.object({
name: z.string(),
completed: z.boolean().default(false),
});
export const createTask = createRoute({
method: "post",
path: "/task",
request: {
body: jsonContent(TaskSchema, "The Task"),
},
responses: {
// ... OK response here
[HttpStatusCodes.UNPROCESSABLE_ENTITY]: jsonContent(
// Creates example schema with validation messages for name / completed
createErrorSchema(TaskSchema),
"Invalid task",
),
},
});
Project bootstrapped with antfu/starter-ts