Skip to content

AsyncAPI — Event-Driven API Specification Guide

DodaTech Updated 2026-06-24 5 min read

In this tutorial, you'll learn about AsyncAPI. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

AsyncAPI is an open-source specification for describing event-driven APIs using a format similar to OpenAPI, enabling documentation and Code Generation for message-based systems like Kafka, RabbitMQ, and WebSocket.

What You'll Learn

By the end of this tutorial, you'll understand the AsyncAPI specification structure, how to define channels and messages, generate code from AsyncAPI files, and integrate event-driven documentation into your workflow.

Why AsyncAPI Matters

REST APIs have OpenAPI — a standard for documentation and Code Generation. Event-driven APIs had no equivalent until AsyncAPI. Without it, teams rely on outdated wikis and tribal knowledge. DodaTech's Durga Antivirus Pro uses AsyncAPI to document its threat event stream, ensuring SIEM partners can integrate without reverse-engineering message formats.

AsyncAPI Document Structure

flowchart TB
    subgraph "AsyncAPI Document"
        A["asyncapi: 2.6.0"] --> B["info: title, version"]
        A --> C["servers: connection details"]
        A --> D["channels: pub/sub paths"]
        D --> E["subscribe: messages received"]
        D --> F["publish: messages sent"]
        E --> G["message: schema (JSON Schema)"]
        F --> G
        A --> H["components: reusable schemas"]
    end
    style A fill:#dbeafe,stroke:#2563eb
    style D fill:#fef3c7,stroke:#f59e0b

Defining an AsyncAPI Specification

asyncapi: 2.6.0
info:
  title: Threat Detection Events API
  version: 1.0.0
  description: Real-time threat event stream from Durga Antivirus Pro

servers:
  kafka:
    url: kafka.dodatech.com:9092
    protocol: kafka
    description: Production Kafka cluster

channels:
  threat/detected:
    subscribe:
      summary: Fired when a new threat is detected
      operationId: onThreatDetected
      message:
        $ref: '#/components/messages/ThreatEvent'
  scan/completed:
    subscribe:
      summary: Fired when a file scan completes
      operationId: onScanCompleted
      message:
        payload:
          type: object
          properties:
            scan_id:
              type: string
            status:
              type: string
              enum: [clean, infected, suspicious]
            duration_ms:
              type: integer

components:
  messages:
    ThreatEvent:
      headers:
        type: object
        properties:
          correlationId:
            type: string
            format: uuid
      payload:
        type: object
        required: [threat_id, severity, timestamp]
        properties:
          threat_id:
            type: string
          severity:
            type: string
            enum: [low, medium, high, critical]
          threat_type:
            type: string
          file_hash:
            type: string
          timestamp:
            type: string
            format: date-time

Generating Code from AsyncAPI

npm install -g @asyncapi/generator

# Generate Node.js subscriber
asyncapi generate fromTemplate threat-events.yaml @asyncapi/nodejs-ws-template

# Generate HTML documentation
asyncapi generate fromTemplate threat-events.yaml @asyncapi/html-template -o docs/

Expected output:

Generator done.
Check out your shiny new generated files at /output/nodejs-ws-template/.

Consuming AsyncAPI Events with Node.js

const { Kafka } = require("kafkajs");

const Kafka = new Kafka({
  clientId: "dodatech-SIEM",
  brokers: ["Kafka.dodatech.com:9092"],
});

async function consumeThreats() {
  const consumer = Kafka.consumer({ groupId: "SIEM-integration" });
  await consumer.connect();
  await consumer.subscribe({ topic: "threat/detected" });

  await consumer.run({
    eachMessage: async ({ topic, partition, message }) => {
      const threat = JSON.parse(message.value.toString());
      console.log(`Threat detected: ${threat.threat_id}`);
      console.log(`Severity: ${threat.severity}`);
      console.log(`Type: ${threat.threat_type}`);
    },
  });
}

consumeThreats().catch(console.error);

Output:

Threat detected: T-20260624-001
Severity: critical
Type: ransomware

Common Errors

1. Confusing Publish and Subscribe

In AsyncAPI, publish means the server publishes messages for clients to receive. subscribe means the server subscribes to messages from clients. Think from the server's perspective, not the client's.

2. Missing Message Schemas

Every channel operation should reference a message schema. Inline payloads work for simple cases, but reusable $ref components keep large specs maintainable.

3. Ignoring Server Definitions

Without server definitions, your spec is documentation-only. Add protocol, URL, and security details so tooling can generate working clients.

4. Not Versioning Event Schemas

Message schemas evolve. Use semantic versioning for your AsyncAPI spec and maintain previous versions for backward compatibility.

5. Overlooking Headers

Correlation IDs, message types, and timestamps belong in headers, not the payload. Define headers separately in the message object.

Practice Questions

1. What problem does AsyncAPI solve?

AsyncAPI provides a standard way to document event-driven APIs (Kafka, Mqtt, WebSocket, AMQP), similar to how OpenAPI documents REST APIs. It enables automated documentation, Code Generation, and validation.

2. What is the difference between publish and subscribe in AsyncAPI?

From the server's perspective: publish means the server publishes (sends) messages that clients can receive. subscribe means the server subscribes to (receives) messages from clients.

3. How do you reference reusable schemas in AsyncAPI?

Use the $ref keyword with JSON Reference syntax: $ref: '#/components/messages/ThreatEvent'. Components can include messages, schemas, security schemes, and parameters.

4. Challenge: Write an AsyncAPI spec for a WebSocket-based chat application with two channels — one for sending messages and one for receiving them. Include user authentication via API key and a message schema with sender, content, and timestamp.

Use a WebSocket server with send/message (publish) and receive/message (subscribe) channels. Define the API key under components.securitySchemes and apply it at the server level. The message schema should require sender, content, and timestamp fields.

Mini Project: AsyncAPI to React Dashboard

Generate a React event dashboard from an AsyncAPI spec using @asyncapi/react-template. The dashboard should display live threat events from the Kafka stream with filtering by severity and threat type.

FAQ

Is AsyncAPI compatible with OpenAPI?

Yes — both use JSON Schema for message/request bodies. AsyncAPI 2.x reuses OpenAPI 3.x concepts like components, security schemes, and server variables. An API can have both an OpenAPI spec (REST endpoints) and an AsyncAPI spec (event streams).

What message brokers does AsyncAPI support?

AsyncAPI is protocol-agnostic. It supports Kafka, RabbitMQ, Mqtt, WebSocket, AMQP, HTTP Webhooks, NATS, and custom protocols via the protocol field in server definitions.

Can I validate messages against AsyncAPI schemas?

Yes — use the AsyncAPI Schema Validator or tools like Spectral with AsyncAPI rulesets to validate messages at runtime against your spec.

What is AsyncAPI 3.0?

AsyncAPI 3.0 introduces operations as first-class citizens, improves reusability with application-level components, and adds better support for multiple protocols in a single spec.

Related Concepts

Webhooks Guide
API Documentation Guide
API Gateway

What's Next

Master OpenAPI specification for REST APIs, then return to AsyncAPI for event-driven systems. Explore API gateways that handle both REST and event-driven traffic.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-24.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro