Serving docs

The openapi() function returns a docs method that serves a Scalar API reference UI, and a spec method that serves the OpenAPI JSON. Add both to your routes:

import { openapi } from "@hectoday/openapi";

const api = openapi(routes, {
  info: { title: "My API", version: "1.0.0" },
});

const app = setup({
  routes: [
    ...routes,
    api.spec(route), // GET /openapi.json
    api.docs(route), // GET /docs
  ],
});

Visit /docs for the interactive Scalar UI, and /openapi.json for the raw spec.

Customizing the paths

Both paths are configurable:

const api = openapi(routes, {
  info: { title: "My API", version: "1.0.0" },
  specPath: "/api/v2/spec.json",
  docsPath: "/reference",
});

Using Swagger UI instead

If you prefer Swagger UI over Scalar, skip api.docs(route) and create your own route:

route.get("/docs", {
  resolve: () => {
    const html = `<!DOCTYPE html>
<html>
<head>
  <title>API Docs</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.11.0/swagger-ui.min.css">
</head>
<body>
  <div id="swagger-ui"></div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.11.0/swagger-ui-bundle.min.js"></script>
  <script>
    SwaggerUIBundle({
      url: '/openapi.json',
      dom_id: '#swagger-ui',
      tryItOutEnabled: true,
    });
  </script>
</body>
</html>`;
    return new Response(html, {
      headers: { "Content-Type": "text/html" },
    });
  },
}),

Make sure the url in SwaggerUIBundle matches your specPath.

Fetching the spec programmatically

# Download the spec
curl http://localhost:3000/openapi.json | jq .

# Generate TypeScript types
npx openapi-typescript http://localhost:3000/openapi.json -o src/api-types.ts

# Validate the spec
npx @redocly/cli lint http://localhost:3000/openapi.json