roas_asyncapi/lib.rs
1//! AsyncAPI Specification — parser and validator.
2//!
3//! Implements the [AsyncAPI Specification](https://www.asyncapi.com/docs/reference/specification/v3.0.0):
4//! a document format describing event-driven APIs — the channels an
5//! application publishes to and consumes from, the messages that travel
6//! over them, and the servers that carry them.
7//!
8//! ## Modules
9//!
10//! - [`common`] — version-agnostic helpers: the `x-` extensions serde
11//! helper, the `$ref` wrapper, untyped protocol bindings, and the
12//! runtime-expression grammar.
13//! - [`validation`] — [`Validate`](validation::Validate) trait,
14//! [`ValidationOptions`](validation::ValidationOptions) flag set,
15//! `Context` / `ValidationError` types.
16//! - `v2_6` — AsyncAPI v2.6 document model + `Validate` impls, behind
17//! the `v2_6` feature.
18//! - `v3_0` — AsyncAPI v3.0 document model + `Validate` impls, behind
19//! the `v3_0` feature.
20//! - `v3_1` — AsyncAPI v3.1 document model + `Validate` impls, behind
21//! the `v3_1` feature (on by default).
22//!
23//! The version modules are named rather than linked above: a link to a
24//! module the current feature set switched off is a broken intra-doc
25//! link, which `cargo doc` reports and `RUSTDOCFLAGS="-D warnings"`
26//! fails on. docs.rs builds this crate with every feature, so both
27//! appear in the sidebar there.
28//!
29//! ## Parsing and validating
30//!
31//! ```rust
32//! # // Gate the example on the v3_1 feature so it stays valid under any
33//! # // feature combination. The hidden cfg block is removed entirely
34//! # // when v3_1 is off, so the doctest compiles to an empty
35//! # // `fn main()` in that case.
36//! # #[cfg(feature = "v3_1")] {
37//! use enumset::EnumSet;
38//! use roas_asyncapi::v3_1::Document;
39//! use roas_asyncapi::validation::Validate;
40//!
41//! // Parse an AsyncAPI document (JSON or YAML).
42//! let doc: Document = serde_json::from_str(r##"{
43//! "asyncapi": "3.1.0",
44//! "info": { "title": "Streetlights", "version": "1.0.0" },
45//! "servers": {
46//! "production": { "host": "broker.example.com:9092", "protocol": "kafka" }
47//! },
48//! "channels": {
49//! "lightMeasured": {
50//! "address": "smartylighting/streetlights/{streetlightId}/lighting/measured",
51//! "parameters": { "streetlightId": { "description": "The streetlight id" } },
52//! "messages": { "lightMeasured": { "name": "LightMeasured" } }
53//! }
54//! },
55//! "operations": {
56//! "receiveLightMeasurement": {
57//! "action": "receive",
58//! "channel": { "$ref": "#/channels/lightMeasured" },
59//! "messages": [ { "$ref": "#/channels/lightMeasured/messages/lightMeasured" } ]
60//! }
61//! }
62//! }"##).unwrap();
63//!
64//! doc.validate(EnumSet::empty()).expect("document is well-formed");
65//! assert_eq!(doc.channels.len(), 1);
66//! # }
67//! ```
68//!
69//! YAML documents work the same way — parse with `serde_yaml_ng` (or
70//! any other YAML crate) into a version module's `Document`.
71//!
72//! ## Scope
73//!
74//! The document model and its validators are the whole surface: this
75//! crate does not resolve `$ref`s across files, apply message /
76//! operation traits, or type protocol bindings. Cross-reference checks
77//! therefore run on document-local pointers only — see
78//! [`ValidationOptions`](validation::ValidationOptions) to require a
79//! self-contained document instead.
80//!
81//! ## Versions
82//!
83//! v2.6.0 (`v2_6`), v3.0.0 (`v3_0`), and v3.1.0 (`v3_1`, the default
84//! feature) are all implemented; enable whichever you need. 2.6 is a
85//! different document rather than an earlier draft of the same one —
86//! channels keyed by path, `publish` / `subscribe` operations, and
87//! parameters carrying full schemas. Each version's schema pins
88//! its `asyncapi` field to exactly that string, so a document is parsed
89//! by one module or rejected. With both features enabled, an
90//! `impl From<v3_0::Document> for v3_1::Document` is available for
91//! upconverting a 3.0 document — v3.1 left the object model untouched,
92//! so nothing is dropped or approximated.
93//!
94//! With `v2_6` and `v3_0` both enabled,
95//! [`v3_0::from_v2_6::convert`] converts a 2.6 document. v3
96//! reorganized the document rather than extending it, so that one is
97//! genuinely lossy: it returns a report saying where a name had to be
98//! invented and what had nowhere to go.
99
100pub mod common;
101pub mod validation;
102
103#[cfg(feature = "v2_6")]
104pub mod v2_6;
105
106#[cfg(feature = "v3_0")]
107pub mod v3_0;
108
109#[cfg(feature = "v3_1")]
110pub mod v3_1;