Schemas
A message type that derives JsonSchema gives its message a payload schema in the document.
The crate re-exports schemars as ruststream::schemars, so a service needs no dependency of its own for the derive.
The schema is JSON Schema draft 07, the draft the AsyncAPI Schema Object extends.
Doc comments on the type and its fields become descriptions in the schema, and the type's doc comment is the message's description.
serde attributes shape the schema as they shape the wire: a renamed field or an Option reads the same in both.
On the attribute path the derive is optional.
A type without it still mounts, and its message carries no payload schema.
build_spec then logs a warning naming the subscription and the type, and messages_without_schema lists the message.
A subscriber(..) registration demands the derive at compile time; undocumented lifts the demand from one registration.
A type that carries its own bytes, on a byte lane, has no schema by design and is not listed as missing one.
The example runs with cargo test --example asyncapi_schemas --features macros,memory,asyncapi.
Example
- Macros
- Manual
/// An order placed by a customer.
#[derive(Debug, Deserialize, JsonSchema)]
struct Order {
/// The order number, unique per shop.
id: u64,
/// What was ordered.
item: String,
/// How many items; one when absent.
quantity: Option<u32>,
}
#[subscriber("orders")]
async fn accept(order: &Order) -> HandlerOutcome {
tracing::info!(order.id, item = %order.item, quantity = ?order.quantity, "accepted");
HandlerOutcome::ack()
}
/// An order placed by a customer.
#[derive(Debug, Deserialize, JsonSchema)]
struct Order {
/// The order number, unique per shop.
id: u64,
/// What was ordered.
item: String,
/// How many items; one when absent.
quantity: Option<u32>,
}
/// The handler `#[subscriber("orders")]` writes for the body.
struct Accept;
impl Handle<Order> for Accept {
fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
tracing::info!(order.id, item = %order.item, quantity = ?order.quantity, "accepted");
ready(Ok(()))
}
}