A TypeSpec emitter that transforms TypeSpec service definitions into AsyncAPI 3.1 specifications. Define your event schemas, channels, and operations in TypeSpec, then generate standards-compliant AsyncAPI YAML.
bun add @lars-artmann/typespec-asyncapiCreate a TypeSpec file (api.tsp):
import "@lars-artmann/typespec-asyncapi";
using TypeSpec.AsyncAPI;
namespace MyAPI;
model Event {
id: string;
timestamp: utcDateTime;
}
@channel("events")
op publishEvent(): Event;Generate AsyncAPI:
bunx tsp compile api.tsp --emit @lars-artmann/typespec-asyncapiOutput (tsp-output/@lars-artmann/typespec-asyncapi/asyncapi.yaml):
asyncapi: 3.1.0
info:
title: MyAPI
version: 1.0.0
channels:
events:
address: events
messages:
Event:
$ref: "#/components/messages/Event"
operations:
publishEvent:
action: send
channel:
$ref: "#/channels/events"
messages:
- $ref: "#/channels/events/messages/Event"
components:
messages:
Event:
name: Event
contentType: application/json
payload:
$ref: "#/components/schemas/Event"
schemas:
Event:
type: object
properties:
id:
type: string
timestamp:
type: string
format: date-time
required:
- id
- timestampDefines a channel address for an operation.
@channel("user.events")
op publishUserEvent(): UserEvent;Marks an operation as sending (publish) or receiving (subscribe).
@channel("orders")
@publish
op publishOrder(): Order;
@channel("notifications")
@subscribe
op subscribeToNotifications(): Notification;Defines server configuration on a namespace. Config accepts #{} (value literal).
@server("production", #{
url: "broker.example.com:9092",
protocol: "kafka",
description: "Production Kafka broker"
})
namespace MyAPI;Configures message metadata on a model.
@message(#{
title: "User Created Event",
description: "Emitted when a new user is created",
contentType: "application/json"
})
model UserCreated {
user: User;
timestamp: utcDateTime;
}Applies protocol-specific bindings.
@channel("events")
@protocol(#{
protocol: "kafka",
partitions: 3,
replicationFactor: 2
})
op publishEvent(): Event;Applies security schemes to operations or namespaces.
@security(#{
name: "oauth2",
scheme: #{
type: "oauth2",
flows: #{
clientCredentials: #{
tokenUrl: "https://auth.example.com/oauth/token"
}
}
}
})
namespace SecureAPI;Categorizes operations, models, or namespaces.
@channel("orders")
@publish
@tags(["orders", "critical"])
op publishOrder(): Order;Specifies correlation ID for message tracing on a model.
@correlationId("$message.header#/correlationId")
model EventWithCorrelation {
payload: string;
}Defines message headers on a model property.
model EventWithHeaders {
@header("X-Trace-Id")
traceId: string;
}Applies generic protocol bindings to operations or models. Binding keys are normalized (websocket→ws) and bindingVersion is auto-injected.
@channel("payments")
@bindings(#{
kafka: #{
partitions: 10,
replicas: 3
}
})
op processPayment(): PaymentResult;Supported protocols for bindings: Kafka (0.5.0), AMQP (0.3.0), MQTT (0.2.0), HTTP (0.3.0), WebSocket (0.1.0).
| Protocol | Server | Channel Bindings | Operation Bindings | Message Bindings |
|---|---|---|---|---|
| Kafka | Yes | Yes (topic, partitions, replicas) | Yes (groupId, clientId) | Yes (key, schemaIdLocation) |
| AMQP | — | Yes (exchange, queue) | Yes (priority, deliveryMode) | Yes (contentEncoding) |
| MQTT | Yes | — | Yes (qos, retain) | Yes |
| WebSocket | Yes | Yes (method, query, headers) | — | — |
| HTTP | — | — | Yes (method, query) | Yes (headers) |
Binding versions are auto-injected when omitted. Protocol aliases (websocket→ws, websockets→ws) are normalized automatically.
git clone https://github.com/LarsArtmann/typespec-asyncapi
cd typespec-asyncapi
bun install
bun run build # Build TypeScript (0 errors)
bun run test # Run tests via vitest (555 pass, 0 fail)
bun run lint # ESLintVersion: 0.2.0-beta Build: 0 TypeScript errors Lint: 0 errors, 0 warnings Tests: 555 pass, 0 fail (0 skip, 0 todo) Output: Validates against AsyncAPI 3.1.0 JSON schema (78 compliance tests) Bindings: Full support for Kafka, AMQP, MQTT, WebSocket, HTTP with auto-versioning
MIT