NATS
This feature provides a client and a service adapter for your interfaces over the NATS protocol, built on the async-nats crate. It lets you connect applications built with the same or different technologies β check all of our templates and the NATS feature in other templates that support it.
- Use a NATS client in place of your local implementation to receive data from a remote service.
- Use a NATS service adapter to expose your implementation as a remote service.
This feature requires api and core.
The NATS server is not part of the template. To run a client and a service (both connect as NATS clients) you need a nats-server reachable by both.
File overview for moduleβ
With our example API definition
Hello World API (click to expand)
schema: apigear.module/1.0
name: io.world
version: "1.0.0"
interfaces:
- name: Hello
properties:
- { name: last, type: Message }
operations:
- name: say
params:
- { name: msg, type: Message }
- { name: when, type: When }
return:
type: int
signals:
- name: justSaid
params:
- { name: msg, type: Message }
enums:
- name: When
members:
- { name: Now, value: 0 }
- { name: Soon, value: 1 }
- { name: Never, value: 2 }
structs:
- name: Message
fields:
- { name: content, type: string }
the following files are generated. The purpose and content of each file is explained below.
πio_world
β£ πsrc
β β£ πnats
β β β£ πmod.rs
β β β£ πhello_client.rs # NATS client adapter for Hello
β β β πhello_service.rs # NATS service adapter for Hello
β β πlib.rs
β£ πtests
β β£ πnats_common.rs # server test helper
β β πnats_hello_test.rs # round-trip tests for Hello
...
The adapters use NATS request/reply for operations and dedicated subjects for properties, signals and the service's state.
NATS client adapterβ
The file πhello_client.rs contains HelloNatsClient, the NATS client version of the Hello interface. It implements HelloTrait, so you use it like a local implementation. It takes a connected async-nats client and subscribes to the interface's subjects.
let nats = async_nats::connect("127.0.0.1:4222").await?;
let client = Arc::new(HelloNatsClient::new(nats));
let _subscription = client.subscribe();
Propertiesβ
A getter (here last()) returns the locally cached value last received from the service. A setter (here set_last()) sends a change request; the local value updates when the service confirms the change. Subscribe to changes through the Publisher returned by publisher().
Operationsβ
Operations use NATS request/reply β the call sends a request and awaits the reply:
let result = client.say(&message, WhenEnum::Now).await;
Signalsβ
Do not emit signals from a client. Subscribe to signals through the Publisher; incoming signal messages are delivered on the matching broadcast channel.
Connectivityβ
The client's subscribe() spawns a background task that subscribes to the property (apigear.io.world.Hello.prop.*), signal (apigear.io.world.Hello.sig.*) and state (apigear.io.world.Hello.state) subjects, and keeps the cache in sync as messages arrive. The service publishes its full state on the .state subject via publish_state(). Because NATS does not retain messages, a client that connects after the service published only sees the state if the service publishes it again β the generated nats_server example re-publishes the state periodically so late-joining clients still receive it.
NATS service adapterβ
The file πhello_service.rs contains HelloNatsService, which wraps a local Hello implementation and exposes it over NATS. It applies incoming operation and property-change requests to your local object and publishes property changes and signals back to clients.
- Properties β a change on your local object (or a client request) is published to all clients.
- Operations β a request is run on your local object; the result is returned only to the requesting client.
- Signals β a signal emitted by your local object is forwarded to all clients.
Use the adaptersβ
The generated examples crate ships ready-to-run nats_server and nats_client binaries. The client connects to the server, hands the connection to the adapter, and subscribes:
use std::sync::Arc;
use std::time::Duration;
let nats = async_nats::connect("127.0.0.1:4222").await.expect("connect to nats-server");
let client = Arc::new(HelloNatsClient::new(nats));
let _subscription = client.subscribe();
// Give the subscriptions and state exchange a moment.
tokio::time::sleep(Duration::from_millis(500)).await;
// Use the client like a local Hello implementation:
let result = client.say(&Default::default(), WhenEnum::Now).await;
println!("say() -> {result:?}");
Start a server, then run the two binaries in separate terminals (override the server URL with the NATS_URL environment variable, default 127.0.0.1:4222):
nats-server -p 4222 &
cargo run -p rust_hello_world_examples --bin nats_server
cargo run -p rust_hello_world_examples --bin nats_client
Testsβ
The NATS feature generates round-trip tests in πtests/nats_hello_test.rs, backed by the helper in πnats_common.rs. They exercise a real client β service round-trip over a live server, so they are marked #[ignore] and skipped by default. Run them against a server the way CI does:
nats-server -p 4222 &
cargo test --manifest-path goldenmaster/Cargo.toml -- --ignored