Speakeasy Logo
Skip to Content
OpenAPI HubFrameworksHono

How to generate an OpenAPI document with Hono

This guide walks you through generating an OpenAPI document for a Hono  API and using Speakeasy to create an SDK based on the generated document.

Here’s what we’ll do:

  1. Add Zod OpenAPI and Scalar UI to a Node.js Hono project.
  2. Generate an OpenAPI document using the Zod OpenAPI Hono middleware.
  3. Improve the generated OpenAPI document to prepare it for code generation.
  4. Use the Speakeasy CLI to generate an SDK based on the OpenAPI document.
  5. Add Speakeasy OpenAPI extensions to improve the generated SDK.

We’ll also take a look at how you can use the generated SDK.

Your Hono project might not be as simple as our example app, but the steps below should translate well to any Hono project.

The OpenAPI creation pipeline

Zod OpenAPI  is Hono middleware that allows you to validate values and types using Zod  and generate an OpenAPI document. We’ll begin by defining data schemas with Zod, then set up the Hono app to generate an OpenAPI document.

The quality of your OpenAPI document determines the quality of generated SDKs and documentation, so we’ll look into ways you can improve the generated document based on the Speakeasy OpenAPI best practices.

We’ll then use the improved OpenAPI document to generate an SDK using Speakeasy.

We’ll explain how to add SDK creation to a CI/CD pipeline so that Speakeasy automatically generates fresh SDKs whenever your Hono API changes in the future.

Finally, we’ll use a simplified example to demonstrate how to use the generated SDK.

Requirements

This guide assumes that you have an existing Hono app and basic familiarity with Hono.

Ensure the following are installed on your machine:

If you’re using the example initial application , add a .env file containing the following environment variables to the root of the initial app project:

Adding the Zod OpenAPI middleware to a Hono project

We’ll use the Zod OpenAPI Hono  middleware to generate an OpenAPI document. We’ll create Zod schemas to validate values and types and to generate part of the OpenAPI document.

Creating Zod schemas

First, install the middleware and Zod:

Next, create a schemas.ts file in the src folder and create Zod schemas for your data:

The z object should be imported from @hono/zod-openapi. Note that Hono also has a Standard Schema validator  that lets you write schemas and validate the incoming values using the same interface for multiple validation libraries that support Standard Schema. Supported validation libraries include Zod, Valibot, and ArkType.

Create schemas for your request-query parameters, messages, and error responses:

Create a types.ts file in the src/lib folder and add the ZodSchema type to it:

Import this type in the src/schemas.ts file.

Replacing the Hono instances with OpenAPIHono

Set up your app to use the OpenAPIHono instance of the Zod OpenAPI middleware instead of the Hono instance. Import the OpenAPIHono class in the src/lib/createApp.ts file:

Remove the Hono import and replace the Hono instances with OpenAPIHono:

The OpenAPIHono class is an extension of the Hono class that gives OpenAPIHono its OpenAPI document-generation functionality.

Defining routes

Let’s split the routes and handlers into separate files for better code organization.

Create a users.routes.ts file in the src/routes/users folder and use the Zod OpenAPI createRoute method to define your routes:

The createRoute function takes in an object that describes the route’s request and possible responses. The Zod schema defines the request and response content. The route types are then exported for use in the route handlers.

Defining route handlers

Create a users.handlers.ts file in the src/routes/users folder and add the following route handlers to it:

Add the following AppRouteHandler type to the src/lib/types.ts file:

The handlers are made type safe by the route types. The request and response data in the Hono context object  is type checked using the schema defined in the routes. If you use an incorrect type, for example, by setting age: to 42, you’ll get a type error.

Configuring the middleware for each endpoint

Replace the code in the src/routes/users/users.index.ts file with the following lines of code:

The openapi method takes the route and the handler as its arguments and configures the Zod OpenAPI middleware for each endpoint on the OpenAPIHono instance.

Configuring and generating the OpenAPI document

Create a file called configureOpenAPI.ts in the src/lib folder and add the following lines of code to it:

The configureOpenAPI function takes in an OpenAPIHono instance and uses the doc31 method to generate an OpenAPI document based on the OpenAPI Specification version 3.1. We can view this document at the '/doc' endpoint. We then pass in the OpenAPI configuration object to the function to add fields to the root object of the OpenAPI document.

Now, pass in the OpenAPIHono app instance to the configureOpenAPI function in the src/app.ts file:

Supported OpenAPI Specification versions in Hono and Speakeasy

Speakeasy currently supports the OpenAPI Specification versions 3.0.x and 3.1.x. We recommend using OpenAPI Specification version 3.1 if possible, as it’s fully compatible with JSON Schema , which gives you access to a large ecosystem of tools and libraries.

Zod OpenAPI Hono can generate an OpenAPI document using version 3.0 or version 3.1 of the OpenAPI Specification. This guide uses version 3.1.

Run the development server npm run dev and open http://localhost:3000/doc to see the OpenAPI document in JSON format:

Adding Scalar UI middleware

Let’s use the Scalar UI middleware  to add an interactive documentation UI for the API.

Install the middleware:

Import the Scalar middleware in the src/lib/configureOpenAPI.ts file:

Add Scalar as a handler for GET requests to the /ui route:

Open your browser and navigate to http://localhost:3000/ui. You should see the Scalar UI with three API endpoints in the sidebar:

Scalar UI endpoints

You can see the parameters required for API endpoints and try out the different API endpoints. In the http://localhost:3000/doc route, you can also view the OpenAPI document in JSON format.

Registering the Zod schemas as reusable OpenAPI component schemas

The request and response content schemas of the OpenAPI document are inline:

Let’s make these schemas reusable by adding them to the OpenAPI Components Object .

Use the .openapi() method on the Zod object to register your Zod schemas as referenced components in the src/schemas.ts file:

This adds your schemas to the OpenAPI components object:

The schemas are referenced using a Reference Object  ($ref), which is a reference identifier that specifies the location (as a URI) of the value being referenced.

Adding OpenAPI metadata to the Zod schemas

Let’s add additional OpenAPI metadata to our schemas.

In the src/schemas.ts file, add example values by passing in an object with an example property to the openapi method:

Define the route parameters for parameter schema:

After adding the OpenAPI metadata to your schemas, you’ll see that your OpenAPI document and Scalar UI will show example values for the schemas used in requests and responses:

Scalar UI POST request example values

You can also view the details of the example data schemas:

Scalar UI example data schema

Adding the OpenAPI operationId using Hono Zod OpenAPI

In the OpenAPI document, each HTTP request has an operationId that identifies the operation. The operationId is also used to generate method names and documentation in SDKs.

To add an operationId, use the operationId property of the createRoute method in the src/routes/users/users.routes.ts file:

Adding OpenAPI tags to Zod OpenAPI Hono routes

Whether you’re building a big application or only have a handful of operations, we recommend adding tags to all your Hono routes so you can group them by tag in generated SDK code and documentation.

Adding OpenAPI tags to routes in Hono

To add an OpenAPI tag to a Zod OpenAPI Hono route, use the tags property to pass in an array of tags as the argument object of the createRoute method call:

Adding metadata to tags

We can add metadata to the tag by passing in a Tag Object , instead of a string, to a tag array item.

Add a tag to the root OpenAPI object openAPIObjectConfig in the src/lib/configureOpenAPI.ts file:

Adding a list of servers to the Hono OpenAPI document

When validating an OpenAPI document, Speakeasy expects a list of servers at the root of the document.

Add a server by adding a servers property to the openAPIObjectConfig object:

Adding retries to your SDK with x-speakeasy-retries

OpenAPI document extensions allow us to add vendor-specific functionality to the document.

  • Extension fields must be prefixed with x-.
  • Speakeasy uses extensions that start with x-speakeasy-.

Let’s add a Speakeasy extension that adds retries to requests from Speakeasy SDKs by adding a top-level x-speakeasy-retries schema to the OpenAPI document. We can also override the retry strategy per operation.

Adding global retries

Apply the Speakeasy retries extension globally by adding the following 'x-speakeasy-retries' property to the openAPIObjectConfig object:

Adding retries per method

To create a unique retry strategy for a single route, add an 'x-speakeasy-retries' property to the createRoute method call’s argument object in the src/routes/users/users.routes.ts file:

Generating an SDK based on your OpenAPI document

Before generating an SDK, we need to save the Hono Zod OpenAPI-generated OpenAPI document to a file. OpenAPI files are written as JSON or YAML; we’ll save it as a YAML file, as it’s easier to read.

Saving the OpenAPI document to a YAML file using a Node.js script

First install the JS-YAML  package:

Then install the types for the package:

Now let’s create a script to convert the OpenAPI object to a YAML file. We’ll use the JS-YAML library to convert the OpenAPI object to a YAML string.

Create a script called generateOpenAPIYamlFile.ts in the src folder and add the following lines of code to it:

This initializes the app and routes, uses the getOpenAPI31Document method to generate an OpenAPI Specification version 3.1 schema object, converts the schema object to a YAML string, and saves it as a file.

Add the following script to your package.json file:

Run the script using the following command:

An openapi.yaml file will be created in your root folder.

Linting the OpenAPI document with Speakeasy

The Speakeasy CLI has an OpenAPI linting command that checks the OpenAPI document for errors and style issues.

Run the linting command:

A lint report will be displayed in the terminal, showing errors, warnings, and hints:

Speakeasy lint report

The Speakeasy Linter has a set of rules that you can configure.

Speakeasy has a VS Code extension  to help you validate your OpenAPI documents for the creation of production-grade SDKs.

Improving and customizing the OpenAPI document using Speakeasy overlays and transformations

Speakeasy transformations are predefined functions that modify the OpenAPI document to improve it for SDK generation. You can use them to remove unused components, filter operations, and format the OpenAPI document.

Overlays let you create overlay documents that can be merged with an OpenAPI document, allowing you to update and use an OpenAPI document without modifying the original OpenAPI document. Overlays are useful when the same OpenAPI document is used in multiple places. Common use cases include adding Speakeasy extensions, adding examples, and hiding internal APIs from a public SDK.

Creating an SDK from the Speakeasy CLI

We’ll use the quickstart command for a guided SDK setup.

Run the command using the Speakeasy CLI:

Following the prompts, provide the OpenAPI document location, name the SDK SDK, and select TypeScript as the SDK language.

In the terminal, you’ll see the steps taken by Speakeasy to create the SDK.

Speakeasy validates the OpenAPI document to check that it’s ready for code generation. Validation issues will be printed in the terminal. The generated SDK will be saved as a folder in your project.

If you get ESLint styling errors, run the speakeasy quickstart command from outside your project.

Speakeasy also suggests improvements for your SDK using Speakeasy Suggest, which is an AI-powered tool in Speakeasy Studio. You can see suggestions by opening the link to your Speakeasy Studio workspace in the terminal:

Speakeasy Studio showing SDK improvement suggestions

Adding SDK generation to your GitHub Actions

The Speakeasy sdk-generation-action repository provides workflows for integrating the Speakeasy CLI into CI/CD pipelines to automatically regenerate SDKs when the OpenAPI document changes.

You can set up Speakeasy to automatically push a new branch to your SDK repositories so that your engineers can review and merge the SDK changes.

For an overview of how to set up automation for your SDKs, see the Speakeasy SDK Workflow Matrix.

Using your SDK

Once you’ve generated your SDK, you can publish it for use. For TypeScript, you can publish it as an npm package.

A quick, non-production-ready way to see your SDK in action is to copy your SDK folder to a frontend TypeScript project and use it there.

For example, you can create a Vite project that uses TypeScript:

Copy the SDK folder from your Hono app to the src directory of your TypeScript Vite project and delete the SDK folder in your Hono project.

In the SDK README.md file, you’ll find documentation about your Speakeasy SDK. TypeScript SDKs generated with Speakeasy include an installable Model Context Protocol (MCP) server  where the various SDK methods are exposed as tools that AI applications can invoke. Your SDK documentation includes instructions for installing the MCP server.

Note that the SDK is not ready for production use. To get it production-ready, follow the steps outlined in your Speakeasy workspace.

The SDK has Zod as a peer dependency, as can be seen in the sdk-typescript/package.json file.

Install the required Zod version:

Replace the code in the src/main.ts file with the following example code taken from the sdk-typescript/docs/sdks/users/README.md file:

Run the Vite dev server:

Enable CORS in your Hono dev server by importing the built-in CORS middleware in the src/app.ts file:

Add the middleware and set the origin to the Vite dev server URL:

Run the Hono dev server as well:

You’ll see the following logged in your browser dev tools console:

The SDK functions are type safe and include TypeScript autocompletion for arguments and outputs.

If you try to access a property that doesn’t exist:

You’ll get a TypeScript error:

Further reading

This guide covered the basics of generating an OpenAPI document using Hono. Here are some resources to help you learn more about OpenAPI, the Hono Zod OpenAPI middleware, and Speakeasy:

Last updated on