Fumadocs

createAsyncAPIPage()

The component for rendering AsyncAPI docs content

Overview

Fumadocs AsyncAPI uses a <AsyncAPIPage /> component to render page contents, it should be a client component.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';

export const AsyncAPIPage = createAsyncAPIPage({
  // config
});

Custom Layout

You can customize how the sections of operations are laid out.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';

export const AsyncAPIPage = createAsyncAPIPage({
  content: {
    renderOperationLayout(slots) {
      return (
        <div className="flex flex-col gap-6">
          {slots.header}
          {slots.connection}
          {slots.description}
          {slots.parameters}
          {slots.messages}
        </div>
      );
    },
  },
});
SlotRenders
headerthe title, on pages with several operations
connectionwhich way messages go, the server and channel address, and the playground
descriptionthe descriptions of operation and its channel, and external documentation
usagecode samples for the selected server, beside the operation on wide pages
authSchemessecurity schemes of the server and operation
parametersaddress parameters, and the query and headers of WebSocket connections
messagesthe messages, with their payload, headers, examples and correlation ID
replythe reply of a request
bindingsprotocol details of the selected server

Direction of Messages

AsyncAPI describes an application with send and receive actions. Pages flip them for readers, who talk to the application: send is shown as Receive, and receive as Send. The sidebar shows them as an arrow into or out of a phone.

Playground

Operations can be tried in a playground: readers connect with the address parameters, query and credentials, send messages from their examples as text, hex or Base64, and see the messages they receive.

A transport connects to the servers of each protocol, WebSocket (ws and wss) is built in.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';
import { sseTransport } from '@fumadocs/asyncapi/playground';

export const AsyncAPIPage = createAsyncAPIPage({
  playground: {
    // by the protocol of servers
    transports: { http: sseTransport, https: sseTransport },
    // set to `false` to disable the playground
    enabled: true,
  },
});

Browser limits

Browsers can't send headers or cookies of other sites with WebSocket connections, only credentials in the query are supported. Pages served over HTTPS can only connect to wss servers.

Server-Sent Events

sseTransport receives the events of http and https servers with fetch, readers can't send messages on it.

  • API keys are sent in headers or the query.
  • HTTP bearer and basic credentials are sent in the Authorization header.

It is opt-in, since webhooks are on http servers too.

Custom Transports

A transport connects to a server and reports what happens through events. For example, MQTT over WebSocket with MQTT.js:

lib/mqtt-transport.ts
import mqtt from 'mqtt';
import type { PlaygroundTransport } from '@fumadocs/asyncapi/playground';

export const mqttTransport: PlaygroundTransport = {
  // the security schemes it applies, they become inputs of the playground
  auth: (scheme) => scheme.type === 'userPassword',
  connect({ url, address, auth }, events) {
    const credentials = auth[0]?.value;
    // the server is the WebSocket listener of broker, like `localhost:9001`
    const client = mqtt.connect(`ws://${new URL(url).host}`, {
      ...(typeof credentials === 'object' && credentials),
      reconnectPeriod: 0,
    });

    client.on('connect', () =>
      client.subscribe(address, (error) => (error ? events.error(error.message) : events.open())),
    );
    client.on('message', (_topic, payload) => events.message(payload.toString()));
    client.on('error', (error) => events.error(error.message));
    client.on('close', () => events.close());

    return {
      send: (data) =>
        client.publish(address, typeof data === 'string' ? data : (new Uint8Array(data) as Buffer)),
      close: () => client.end(),
    };
  },
};
components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';
import { mqttTransport } from '@/lib/mqtt-transport';

export const AsyncAPIPage = createAsyncAPIPage({
  playground: {
    transports: { mqtt: mqttTransport },
  },
});

See PlaygroundTransport for the details.

Code Samples

Operations show how to receive or send their messages on the selected server, in JavaScript and Python.

ProtocolJavaScriptPython
ws, wssWebSocketwebsockets
mqtt, mqtts, secure-mqttmqttpaho-mqtt
kafka, kafka-securekafkajsconfluent-kafka
amqp, amqpsamqplibpika
nats@nats-io/transport-nodenats-py

Add generators with codeUsages, or replace the default ones:

components/api-page.tsx
'use client';
import {
  createAsyncAPIPage,
  createCodeUsageGeneratorRegistry,
  registerDefaultCodeUsages,
} from '@fumadocs/asyncapi/ui';

// leave out the defaults to start from scratch
const codeUsages = registerDefaultCodeUsages(createCodeUsageGeneratorRegistry());

codeUsages.add('websocat', {
  label: 'websocat',
  lang: 'bash',
  // `url` is the URL to connect to WebSocket channels
  generate({ protocol }, { url }) {
    // hidden on other protocols
    if (protocol !== 'ws' && protocol !== 'wss') return '';
    return `websocat "${url}"`;
  },
});

export const AsyncAPIPage = createAsyncAPIPage({ codeUsages });

Prop

Type

Operations can have their own samples in x-codeSamples, they replace the generated ones of the same lang, and source: false removes one.

operations:
  receiveLightMeasurement:
    action: receive
    x-codeSamples:
      - lang: js
        label: SDK
        source: |
          lights.onMeasured((event) => console.log(event));
      - lang: python
        source: false

Schema UI

Customize how JSON schemas are rendered, or disable schema examples.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';

export const AsyncAPIPage = createAsyncAPIPage({
  schemaUI: {
    showExample: true,
    render(options, ctx) {
      // fully custom schema renderer
      return ctx.SchemaUI(options);
    },
  },
});

TypeScript Definitions

Payloads and headers have a button to copy their TypeScript definitions, generated with @fumari/json-schema-ts.

Like the schemas on pages, they leave out readOnly properties of messages readers send, and writeOnly properties of messages they receive.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';

export const AsyncAPIPage = createAsyncAPIPage({
  // or `(schema, ctx) => string | undefined` to generate your own
  generateTypeScriptDefinitions: false,
});

Internationalization

Assuming you have configured Internationalization at UI level:

layout.shared.tsx
import { defineI18n } from 'fumadocs-core/i18n';
import { uiTranslations } from 'fumadocs-ui/i18n';
import { asyncapiTranslations } from '@fumadocs/asyncapi/i18n';

const i18n = defineI18n({
  languages: ['en', 'cn'],
  defaultLanguage: 'en',
});

export const translations = i18n
  .translations()
  .extend(uiTranslations())
  .extend(asyncapiTranslations())
  .add({
    cn: {
      displayName: 'Chinese',
      'Messages(operation page)': '消息',
    },
  });

See Translations for more details.

Syntax Highlighting

AsyncAPI pages highlight code blocks with Shiki, pass a highlighter to customize it.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';
import { highlighter } from '@/lib/highlighter';

export const AsyncAPIPage = createAsyncAPIPage({ highlighter });

Custom Components

Override the default heading and code block components.

components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';

export const AsyncAPIPage = createAsyncAPIPage({
  components: {
    Heading({ id, depth, ...props }) {
      const Tag = `h${depth}` as const;
      return <Tag id={id} {...props} />;
    },
    CodeBlock({ lang, code }) {
      return <pre data-lang={lang}>{code}</pre>;
    },
  },
});

Customise UI

For customisations beyond the available options, you can install the UI into your codebase with Fumadocs CLI.

Full UI

The entire UI of API pages, built on the headless layer.

npx @fumadocs/cli add asyncapi/page

It installs <AsyncAPIPage /> itself, your components/api-page.tsx is no longer needed.

mdx-components.tsx
import { AsyncAPIPage } from '@/components/api-page'; 
import { AsyncAPIPage } from '@/components/asyncapi/page'; 

Operation

The UI of a single operation, including its channel, messages and bindings.

npx @fumadocs/cli add asyncapi/operation

Playground

The playground, built on usePlayground().

npx @fumadocs/cli add asyncapi/playground
components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';
import { Operation } from '@/components/asyncapi/operation';

export const AsyncAPIPage = createAsyncAPIPage({
  components: {
    Operation,
  },
});

Schema UI

The UI of JSON schemas, shared with the other API integrations. Its state comes from <SchemaUIProvider />.

npx @fumadocs/cli add api-docs/schema
components/api-page.tsx
'use client';
import { createAsyncAPIPage } from '@fumadocs/asyncapi/ui';
import { Schema } from '@/components/api/schema';

export const AsyncAPIPage = createAsyncAPIPage({
  components: {
    SchemaUI: Schema,
  },
});

How is this guide?

Last updated on