Skip to content
✨ Publier v1 is live — a polished docs platform built for the open web.
On this page

OpenAPI

Generate OpenAPI 3.x MDX pages and use the partial AsyncAPI content-source and rendering APIs.

@publier/openapi generates MDX pages from OpenAPI 3.x specs and provides API rendering components. The API Reference section of this site was built with it. AsyncAPI support is a separate, partial content-source and component API, described below.

Install

Terminal window
pnpm add @publier/openapi yaml

Quickstart

    1. Place your spec at the project root:

      openapi.yaml
      openapi: "3.1.0"
      info:
      title: My API
      version: "1.0.0"
      paths:
      /users:
      get:
      operationId: listUsers
      summary: List users
      tags: [Users]
      responses:
      "200":
      description: A list of users
    2. Write a generation script:

      scripts/generate-api.ts
      import { generateFiles } from '@publier/openapi/generate';
      import { readFileSync } from 'node:fs';
      import { parse } from 'yaml';
      const spec = parse(readFileSync('./openapi.yaml', 'utf-8'));
      generateFiles({
      spec,
      outputDir: './src/content/docs/api',
      groupBy: 'tag', // group pages by tag (or 'path')
      per: 'operation', // one MDX file per operation
      });
    3. Run the generator:

      Terminal window
      bun run scripts/generate-api.ts

      This writes one MDX file per operation and optional meta.yaml inputs for custom routes. The default docs route discovers the generated MDX pages, but does not read those metadata files.

    4. Add an npm script for convenience:

      package.json
      {
      "scripts": {
      "gen:api": "bun run scripts/generate-api.ts"
      }
      }
    5. Label and position the API group. Configure the default docs sidebar in publier.config.yaml:

      publier.config.yaml
      docs:
      sidebar:
      meta:
      api: { label: API Reference, order: 30 }
      api/users: { label: Users, order: 1 }
      api/orders: { label: Orders, order: 2 }
      api/webhooks: { label: Webhooks, order: 3 }

      Match the keys to the directories emitted from your spec. A custom docs route can instead read the generated meta.yaml files with readMetaYaml() and pass the result to buildSidebar(); creating those files alone does not configure the default sidebar. See Configuration.

    6. Run publier dev — generated pages render with interactive components for parameters, request bodies, and code samples.

Code samples

Request examples are generated automatically in six languages: cURL, JavaScript (fetch), Python (requests), Go (net/http), Java (HttpClient), and C#.

To provide your own, add x-codeSamples to the operation in your spec — the generator uses those instead.

Server-side API

For programmatic access at build time:

import { createOpenAPI } from '@publier/openapi/server';
const openapi = createOpenAPI({ input: ['./openapi.yaml'] });
const op = await openapi.getOperation('listUsers');
const get = await openapi.getOperationByPath('/users', 'get');
const tag = await openapi.getOperationsByTag('Users');
const nav = await openapi.getNavigation({ slugPrefix: 'api' });

Multi-spec merging just works:

const merged = createOpenAPI({
input: ['./public-api.yaml', './admin-api.yaml'],
});

AsyncAPI

generateFiles() handles OpenAPI paths and webhooks; it does not generate MDX from AsyncAPI channels. Neither integrations.asyncapi nor integrations.openapi runs a generator today.

The package exports asyncapiSource() for channel page metadata and a navigation tree:

import { asyncapiSource } from '@publier/openapi';
import { readFileSync } from 'node:fs';
import { parse } from 'yaml';
const spec = parse(readFileSync('./asyncapi.yaml', 'utf-8'));
const source = asyncapiSource({ spec, baseUrl: '/async-reference' });
const pages = await source.getPages();
const tree = await source.getPageTree();

This does not write files, register Astro routes, or render page bodies. You must supply your own route and layout. The source correlates operations from the AsyncAPI 3-style top-level operations map with channel references; it does not translate AsyncAPI 2 publish/subscribe operations into that model.

For rendering in your own pages, the existing component exports are:

---
import AsyncChannel from '@publier/openapi/components/async-channel';
import AsyncMessage from '@publier/openapi/components/async-message';
---

AsyncChannel takes channelName, channel, and an operations array of { name, operation, messages } objects, with optional servers. AsyncMessage takes a message. These are rendering building blocks, not an automatic AsyncAPI documentation pipeline.

Components

ComponentPurpose
APIReferenceSingle endpoint — params, body, responses
APIPageFull page layout for an operation
APIPlaygroundInteractive “try it” panel
SchemaViewJSON Schema renderer
CodeSamplesMulti-language request examples
AsyncChannelAsyncAPI channel view
AsyncMessageAsyncAPI message schema

Import from subpath exports:

import APIReference from '@publier/openapi/components/api-reference';

Interactive requests

APIPlayground is a separate component; generated APIReference pages do not automatically include it. Pass the parsed specification so the playground can resolve root security requirements and operation overrides:

---
import APIPlayground from '@publier/openapi/components/api-playground';
import { parse } from 'yaml';
import { readFileSync } from 'node:fs';
const spec = parse(readFileSync('./openapi.yaml', 'utf8'));
const operation = spec.paths['/users'].get;
---
<APIPlayground method="get" path="/users" operation={operation} spec={spec} />

The playground inherits root security unless the operation overrides it; security: [] removes authentication. A selector chooses between alternatives, while schemes in one requirement are applied together. API keys use their declared header or query name. HTTP bearer, HTTP basic, and manually obtained OAuth/OpenID access tokens are supported. The playground does not run an OAuth login flow.

Cookie authentication can opt in to sending existing browser cookies. You cannot type an arbitrary Cookie header; browser cookie, SameSite, and CORS policies still apply. Use a server that permits requests from your docs origin, and include that API origin in your host’s Content Security Policy connect-src directive. Unsupported or unresolved schemes produce a visible error.

Request bodies use the selected media type from requestBody.content. JSON and text are sent as raw text. For application/x-www-form-urlencoded and multipart/form-data, enter a JSON object of scalar fields. Fetch supplies the multipart boundary. File uploads and nested form encoding are not supported. GET and HEAD requests omit the body and do not add a JSON Content-Type.

Existing standalone playgrounds without a spec retain manual bearer and X-API-Key fields. Pass spec to use your API’s declared authentication.