AsyncAPI
Supported versions: 2.0 -> 3.0
If you arrive from the AsyncAPI community, you might be wondering what this project is and how does it relate?
The Codegen Project was started because of a need for a code generator that;
- could easily be integrated into development workflows
- can easily be extended or customized to specific use-cases
- forms a community across communities in languages and standards
- are financially sustainable long term through open source at it's core.
There is a lot of overlap with existing tooling, however the idea is to form the same level of quality that the OpenAPI Generator provides to OpenAPI community for HTTP, for AsyncAPI and any protocol (including HTTP), and the usability of the Apollo GraphQL generator. How are we gonna achieve it? Together, and a roadmap.
Presets | AsyncAPI |
---|---|
payloads | ✔️ |
parameters | ✔️ |
headers | ✔️ |
types | ✔️ |
channels | ✔️ |
client | ✔️ |
custom | ✔️ |
Basic AsyncAPI Document Structure
Here's a complete basic AsyncAPI document example to get you started:
{
"asyncapi": "3.0.0",
"info": {
"title": "User Service API",
"version": "1.0.0",
"description": "API for user management events"
},
"channels": {
"userSignedup": {
"address": "user/signedup/{userId}/{region}",
"parameters": {
"userId": {
"description": "The unique identifier for the user"
},
"region": {
"description": "The geographic region",
"enum": ["us-east", "us-west", "eu-central"]
}
},
"messages": {
"UserSignedUp": {
"$ref": "#/components/messages/UserSignedUp"
}
}
}
},
"operations": {
"sendUserSignedup": {
"action": "send",
"channel": {
"$ref": "#/channels/userSignedup"
},
"messages": [
{
"$ref": "#/channels/userSignedup/messages/UserSignedUp"
}
]
},
"receiveUserSignedup": {
"action": "receive",
"channel": {
"$ref": "#/channels/userSignedup"
},
"messages": [
{
"$ref": "#/channels/userSignedup/messages/UserSignedUp"
}
]
}
},
"components": {
"messages": {
"UserSignedUp": {
"payload": {
"$ref": "#/components/schemas/UserSignedUpPayload"
},
"headers": {
"$ref": "#/components/schemas/UserHeaders"
}
}
},
"schemas": {
"UserSignedUpPayload": {
"type": "object",
"properties": {
"display_name": {
"type": "string",
"description": "Name of the user"
},
"email": {
"type": "string",
"format": "email",
"description": "Email of the user"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "When the user was created"
}
},
"required": ["display_name", "email"]
},
"UserHeaders": {
"type": "object",
"properties": {
"correlation_id": {
"type": "string",
"description": "Correlation ID for tracking"
},
"source": {
"type": "string",
"description": "Source system"
}
}
}
}
}
}
Extensions
To customize the code generation through the AsyncAPI document, use the x-the-codegen-project
extension object with the following properties:
Channel Extensions
channelName
, string, customize the name of the functions generated for the channel, use this to overwrite the automatically determined name for models and functions. This will be used by the following generators; payloads, parameters and channels.
functionTypeMapping
, ChannelFunctionTypes, customize which generators to generate for the given channel, use this to specify further which functions we render. This will be used by the following generators; channels.
Example: Custom Channel Configuration
{
"asyncapi": "3.0.0",
"info": {
"title": "Custom Channel Example",
"version": "1.0.0"
},
"channels": {
"user-events": {
"address": "events/user/{action}",
"parameters": {
"action": {
"enum": ["created", "updated", "deleted"]
}
},
"messages": {
"UserEvent": {
"payload": {
"type": "object",
"properties": {
"userId": {"type": "string"},
"action": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"}
}
}
}
},
"x-the-codegen-project": {
"channelName": "UserEventChannel",
"functionTypeMapping": ["event_source_express", "kafka_publish"]
}
}
}
}
Operation Extensions
functionTypeMapping
, ChannelFunctionTypes, customize which generators to generate for the given operation, use this to specify further which functions we render. This will be used by the following generators; channels.
Example: Custom Operation Configuration
{
"asyncapi": "3.0.0",
"info": {
"title": "Custom Operation Example",
"version": "1.0.0"
},
"operations": {
"publishUserEvent": {
"action": "send",
"channel": {
"$ref": "#/channels/user-events"
},
"messages": [
{"$ref": "#/channels/user-events/messages/UserEvent"}
],
"x-the-codegen-project": {
"functionTypeMapping": ["kafka_publish"]
}
},
"subscribeToUserEvents": {
"action": "receive",
"channel": {
"$ref": "#/channels/user-events"
},
"messages": [
{"$ref": "#/channels/user-events/messages/UserEvent"}
],
"x-the-codegen-project": {
"functionTypeMapping": ["kafka_subscribe"]
}
}
}
}
Protocol Support
HTTP Client
Use HTTP bindings to generate HTTP client code. Supports all standard HTTP methods and status codes.
Example: REST API with Multiple HTTP Methods
{
"asyncapi": "3.0.0",
"info": {
"title": "User Management API",
"version": "1.0.0"
},
"channels": {
"users": {
"address": "/users/{userId}",
"parameters": {
"userId": {
"description": "User identifier"
}
},
"messages": {
"UserRequest": {
"payload": {
"$ref": "#/components/schemas/User"
}
},
"UserResponse": {
"payload": {
"$ref": "#/components/schemas/User"
},
"bindings": {
"http": {
"statusCode": 200
}
}
},
"NotFound": {
"payload": {
"type": "object",
"properties": {
"error": {"type": "string"},
"code": {"type": "string"}
}
},
"bindings": {
"http": {
"statusCode": 404
}
}
}
}
}
},
"operations": {
"createUser": {
"action": "send",
"channel": {"$ref": "#/channels/users"},
"messages": [{"$ref": "#/channels/users/messages/UserRequest"}],
"bindings": {
"http": {"method": "POST"}
},
"reply": {
"channel": {"$ref": "#/channels/users"},
"messages": [{"$ref": "#/channels/users/messages/UserResponse"}]
},
"x-the-codegen-project": {
"functionTypeMapping": ["http_client"]
}
},
"getUser": {
"action": "send",
"channel": {"$ref": "#/channels/users"},
"messages": [],
"bindings": {
"http": {"method": "GET"}
},
"reply": {
"channel": {"$ref": "#/channels/users"},
"messages": [
{"$ref": "#/channels/users/messages/UserResponse"},
{"$ref": "#/channels/users/messages/NotFound"}
]
},
"x-the-codegen-project": {
"functionTypeMapping": ["http_client"]
}
},
"updateUser": {
"action": "send",
"channel": {"$ref": "#/channels/users"},
"messages": [{"$ref": "#/channels/users/messages/UserRequest"}],
"bindings": {
"http": {"method": "PUT"}
},
"reply": {
"channel": {"$ref": "#/channels/users"},
"messages": [{"$ref": "#/channels/users/messages/UserResponse"}]
},
"x-the-codegen-project": {
"functionTypeMapping": ["http_client"]
}
},
"deleteUser": {
"action": "send",
"channel": {"$ref": "#/channels/users"},
"messages": [],
"bindings": {
"http": {"method": "DELETE"}
},
"reply": {
"channel": {"$ref": "#/channels/users"},
"messages": [{"$ref": "#/channels/users/messages/UserResponse"}]
},
"x-the-codegen-project": {
"functionTypeMapping": ["http_client"]
}
}
},
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"email": {"type": "string", "format": "email"},
"created_at": {"type": "string", "format": "date-time"}
},
"required": ["name", "email"]
}
}
}
}
Kafka
Generate Kafka producers and consumers with proper serialization.
Example: Kafka Event Streaming
{
"asyncapi": "3.0.0",
"info": {
"title": "Order Processing Events",
"version": "1.0.0"
},
"channels": {
"order-events": {
"address": "orders.{eventType}.{region}",
"parameters": {
"eventType": {
"enum": ["created", "updated", "cancelled", "completed"]
},
"region": {
"enum": ["us", "eu", "asia"]
}
},
"messages": {
"OrderEvent": {
"payload": {
"$ref": "#/components/schemas/OrderEvent"
},
"headers": {
"$ref": "#/components/schemas/EventHeaders"
}
}
}
}
},
"operations": {
"publishOrderEvent": {
"action": "send",
"channel": {"$ref": "#/channels/order-events"},
"messages": [{"$ref": "#/channels/order-events/messages/OrderEvent"}],
"bindings": {
"kafka": {
"clientId": "order-service",
"groupId": "order-processors"
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["kafka_publish"]
}
},
"subscribeToOrderEvents": {
"action": "receive",
"channel": {"$ref": "#/channels/order-events"},
"messages": [{"$ref": "#/channels/order-events/messages/OrderEvent"}],
"bindings": {
"kafka": {
"groupId": "order-processors",
"clientId": "order-consumer"
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["kafka_subscribe"]
}
}
},
"components": {
"schemas": {
"OrderEvent": {
"type": "object",
"properties": {
"orderId": {"type": "string"},
"customerId": {"type": "string"},
"amount": {"type": "number"},
"currency": {"type": "string"},
"status": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"}
},
"required": ["orderId", "customerId", "amount", "status"]
},
"EventHeaders": {
"type": "object",
"properties": {
"correlationId": {"type": "string"},
"source": {"type": "string"},
"version": {"type": "string"}
}
}
}
}
}
NATS
Generate NATS request/reply patterns and pub/sub functionality.
Example: NATS Request-Reply Pattern
{
"asyncapi": "3.0.0",
"info": {
"title": "User Service NATS API",
"version": "1.0.0"
},
"channels": {
"user-service": {
"address": "user.service.{operation}",
"parameters": {
"operation": {
"enum": ["get", "create", "update", "delete"]
}
},
"messages": {
"UserRequest": {
"payload": {
"$ref": "#/components/schemas/UserRequest"
}
},
"UserResponse": {
"payload": {
"$ref": "#/components/schemas/UserResponse"
}
}
}
}
},
"operations": {
"requestUserOperation": {
"action": "send",
"channel": {"$ref": "#/channels/user-service"},
"messages": [{"$ref": "#/channels/user-service/messages/UserRequest"}],
"reply": {
"channel": {"$ref": "#/channels/user-service"},
"messages": [{"$ref": "#/channels/user-service/messages/UserResponse"}]
},
"x-the-codegen-project": {
"functionTypeMapping": ["nats_request"]
}
},
"replyToUserOperation": {
"action": "receive",
"channel": {"$ref": "#/channels/user-service"},
"messages": [{"$ref": "#/channels/user-service/messages/UserRequest"}],
"reply": {
"channel": {"$ref": "#/channels/user-service"},
"messages": [{"$ref": "#/channels/user-service/messages/UserResponse"}]
},
"x-the-codegen-project": {
"functionTypeMapping": ["nats_reply"]
}
}
},
"components": {
"schemas": {
"UserRequest": {
"type": "object",
"properties": {
"operation": {"type": "string"},
"userId": {"type": "string"},
"data": {"type": "object"}
},
"required": ["operation"]
},
"UserResponse": {
"type": "object",
"properties": {
"success": {"type": "boolean"},
"data": {"type": "object"},
"error": {"type": "string"}
},
"required": ["success"]
}
}
}
}
MQTT
Generate MQTT publish/subscribe clients with QoS levels.
Example: IoT Device Communications
{
"asyncapi": "3.0.0",
"info": {
"title": "IoT Device Management",
"version": "1.0.0"
},
"channels": {
"device-telemetry": {
"address": "devices/{deviceId}/telemetry/{sensorType}",
"parameters": {
"deviceId": {
"description": "Unique device identifier"
},
"sensorType": {
"enum": ["temperature", "humidity", "pressure", "motion"]
}
},
"messages": {
"TelemetryData": {
"payload": {
"$ref": "#/components/schemas/TelemetryData"
}
}
}
},
"device-commands": {
"address": "devices/{deviceId}/commands",
"parameters": {
"deviceId": {
"description": "Unique device identifier"
}
},
"messages": {
"DeviceCommand": {
"payload": {
"$ref": "#/components/schemas/DeviceCommand"
}
}
}
}
},
"operations": {
"publishTelemetry": {
"action": "send",
"channel": {"$ref": "#/channels/device-telemetry"},
"messages": [{"$ref": "#/channels/device-telemetry/messages/TelemetryData"}],
"bindings": {
"mqtt": {
"qos": 1,
"retain": false
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["mqtt_publish"]
}
},
"subscribeToTelemetry": {
"action": "receive",
"channel": {"$ref": "#/channels/device-telemetry"},
"messages": [{"$ref": "#/channels/device-telemetry/messages/TelemetryData"}],
"bindings": {
"mqtt": {
"qos": 1
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["mqtt_subscribe"]
}
},
"sendCommand": {
"action": "send",
"channel": {"$ref": "#/channels/device-commands"},
"messages": [{"$ref": "#/channels/device-commands/messages/DeviceCommand"}],
"bindings": {
"mqtt": {
"qos": 2,
"retain": true
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["mqtt_publish"]
}
}
},
"components": {
"schemas": {
"TelemetryData": {
"type": "object",
"properties": {
"deviceId": {"type": "string"},
"sensorType": {"type": "string"},
"value": {"type": "number"},
"unit": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"},
"location": {
"type": "object",
"properties": {
"latitude": {"type": "number"},
"longitude": {"type": "number"}
}
}
},
"required": ["deviceId", "sensorType", "value", "timestamp"]
},
"DeviceCommand": {
"type": "object",
"properties": {
"command": {"type": "string"},
"parameters": {"type": "object"},
"commandId": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"}
},
"required": ["command", "commandId"]
}
}
}
}
AMQP
Generate AMQP producers and consumers for message queuing.
Example: Order Processing Queue
{
"asyncapi": "3.0.0",
"info": {
"title": "Order Processing Queue",
"version": "1.0.0"
},
"channels": {
"order-queue": {
"address": "orders.processing",
"messages": {
"OrderMessage": {
"payload": {
"$ref": "#/components/schemas/Order"
},
"headers": {
"$ref": "#/components/schemas/MessageHeaders"
}
}
}
},
"order-dlq": {
"address": "orders.dead-letter",
"messages": {
"FailedOrderMessage": {
"payload": {
"$ref": "#/components/schemas/FailedOrder"
}
}
}
}
},
"operations": {
"publishOrder": {
"action": "send",
"channel": {"$ref": "#/channels/order-queue"},
"messages": [{"$ref": "#/channels/order-queue/messages/OrderMessage"}],
"bindings": {
"amqp": {
"exchange": {
"name": "orders",
"type": "topic",
"durable": true
},
"routingKey": "order.created"
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["amqp_publish"]
}
},
"consumeOrders": {
"action": "receive",
"channel": {"$ref": "#/channels/order-queue"},
"messages": [{"$ref": "#/channels/order-queue/messages/OrderMessage"}],
"bindings": {
"amqp": {
"queue": {
"name": "order-processing-queue",
"durable": true,
"exclusive": false,
"autoDelete": false
},
"ack": true
}
},
"x-the-codegen-project": {
"functionTypeMapping": ["amqp_consume"]
}
}
},
"components": {
"schemas": {
"Order": {
"type": "object",
"properties": {
"orderId": {"type": "string"},
"customerId": {"type": "string"},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {"type": "string"},
"quantity": {"type": "integer"},
"price": {"type": "number"}
}
}
},
"totalAmount": {"type": "number"},
"currency": {"type": "string"},
"orderDate": {"type": "string", "format": "date-time"}
},
"required": ["orderId", "customerId", "items", "totalAmount"]
},
"FailedOrder": {
"type": "object",
"properties": {
"orderId": {"type": "string"},
"error": {"type": "string"},
"retryCount": {"type": "integer"},
"failedAt": {"type": "string", "format": "date-time"}
}
},
"MessageHeaders": {
"type": "object",
"properties": {
"messageId": {"type": "string"},
"correlationId": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"},
"priority": {"type": "integer", "minimum": 0, "maximum": 255}
}
}
}
}
}
EventSource
Generate Server-Sent Events (SSE) implementations for real-time updates.
Example: Real-time Notifications
{
"asyncapi": "3.0.0",
"info": {
"title": "Real-time Notifications",
"version": "1.0.0"
},
"channels": {
"user-notifications": {
"address": "/events/users/{userId}/notifications",
"parameters": {
"userId": {
"description": "User identifier for targeted notifications"
}
},
"messages": {
"Notification": {
"payload": {
"$ref": "#/components/schemas/Notification"
}
},
"SystemAlert": {
"payload": {
"$ref": "#/components/schemas/SystemAlert"
}
}
}
},
"live-updates": {
"address": "/events/live/{topic}",
"parameters": {
"topic": {
"enum": ["stock-prices", "sports-scores", "weather-alerts"]
}
},
"messages": {
"LiveUpdate": {
"payload": {
"$ref": "#/components/schemas/LiveUpdate"
}
}
}
}
},
"operations": {
"streamUserNotifications": {
"action": "send",
"channel": {"$ref": "#/channels/user-notifications"},
"messages": [
{"$ref": "#/channels/user-notifications/messages/Notification"},
{"$ref": "#/channels/user-notifications/messages/SystemAlert"}
],
"x-the-codegen-project": {
"functionTypeMapping": ["event_source_express"]
}
},
"streamLiveUpdates": {
"action": "send",
"channel": {"$ref": "#/channels/live-updates"},
"messages": [{"$ref": "#/channels/live-updates/messages/LiveUpdate"}],
"x-the-codegen-project": {
"functionTypeMapping": ["event_source_express"]
}
}
},
"components": {
"schemas": {
"Notification": {
"type": "object",
"properties": {
"id": {"type": "string"},
"userId": {"type": "string"},
"type": {"type": "string", "enum": ["info", "warning", "error", "success"]},
"title": {"type": "string"},
"message": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"},
"actionUrl": {"type": "string", "format": "uri"},
"read": {"type": "boolean", "default": false}
},
"required": ["id", "userId", "type", "title", "message", "timestamp"]
},
"SystemAlert": {
"type": "object",
"properties": {
"alertId": {"type": "string"},
"severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]},
"service": {"type": "string"},
"message": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"},
"resolved": {"type": "boolean", "default": false}
},
"required": ["alertId", "severity", "service", "message", "timestamp"]
},
"LiveUpdate": {
"type": "object",
"properties": {
"topic": {"type": "string"},
"data": {"type": "object"},
"timestamp": {"type": "string", "format": "date-time"},
"sequence": {"type": "integer"}
},
"required": ["topic", "data", "timestamp"]
}
}
}
}
FAQ
How does it relate to AsyncAPI Generator and templates?
It is fairly similar in functionality except in some key areas.
Templates are similar to presets except you can bind presets together to make it easier to render code down stream.
The AsyncAPI Generator is like the core of the Codegen Project, however it does not enable different inputs than AsyncAPI documents.
Can I mix multiple protocols in one document?
Yes! You can define operations with different protocol bindings in the same AsyncAPI document. Use the x-the-codegen-project
extension to specify which generators to use for each operation.
How do I handle versioning?
Use the info.version
field in your AsyncAPI document and consider using separate documents for major version changes. You can also use channel addressing patterns to include version information.
Can I customize the generated code structure?
Yes, use the x-the-codegen-project
extension properties to customize channel names, function mappings, and other generation aspects. If you want full control, use the custom preset