Working with the bus
The module fruster-bus
is a central piece when developing services in fruster.
In its simples form fruster-bus
is just a wrapper for the underlying nats client to subscribe on subjects and send messages. Apart from that it also adds the following capabilities to support key concepts in Fruster:
- Schema validation of requests and responses
- Permission checks
- Aware of the structure of fruster message model
- Emit metadata about exposed endpoints
- Handles and throws errors in a Fruster compatible way
Connecting to bus
When a service is started it should immediately attempt to connect to the bus. This is done by entering the nats url:
import bus from "fruster-bus"; async function start() { await bus.connect("nats://localhost:4222"); // Bus is connected, now define subscribes etc }
Underlying the nats client will connect to nats and if it looses the connection it will attempt to reconnect.
Subscribing to subjects
You need to subscribe to a subject in order to get messages routed to the service.
This will subscribe to subject http.get.car
(which corresponds to HTTP request GET /car
) and return a response:
import bus from "fruster-bus"; bus.subscribe({ subject: "http.get.car", handle: (req) => { return { status: 200, data: "This is the response", }; }, });
Request and response schemas
You can easily define which schema to use while defining the subscription.
This can be achieved either by entering the id of the JSON schema:
bus.subscribe({ subject: "http.get.car", responseSchema: "CarSchema", // id of schema handle: (req) => { return { status: 200, data: "This is the response", }; }, });
Or by referencing the actual schema file if imported as a module:
import CarSchema from "../schemas/CarSchema"; bus.subscribe({ subject: "http.get.car", responseSchema: CarSchema, // module reference handle: (req) => { return { status: 200, data: "This is the response", }; }, });
Send a request
A service can send a request to other service to get data.
const { status, data } = await bus.request({ subject: "user-service.get-user", message: { reqId: "42571411-2161-464f-9c52-f6b84aee9ffe", data: { // payload here }, }, });
reqId
is used to track a message sequence during logging and debugging. API gateway will automatically assign a reqId but after that you need to make sure to pass the reqId to any subsequent request.
Any error response from request will be thrown and need to be handled:
try { const { status, data } = await bus.request({ subject: "user-service.get-user", message: { reqId: "42571411-2161-464f-9c52-f6b84aee9ffe", data: { // payload here }, }, }); } catch (err) { console.log("Got error", err.status); }
Not however that fruster-bus
will automatically handle any fruster errors that bubbles up, so in many cases no additional error handling is necessary.
Mocked mode
To simplify testing fruster-bus
has the built in capability to run in mocked mode. That means that it will not actually connect to NATS bus but instead only mimic the bus in memory.
This is enabled when enter nats url nats://mock
. Needless to say, but this should only be used for testing purposes to mock invocations to a real message bus.
await bus.connect("nats://mock");