Skip to main content
Docs: template-rust

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.
note

This feature requires api and core.

tip

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