Messaging

Services communicates with surrounding world and each other by sending and receiving JSON messages over the message bus.

The API gateway will translate incoming HTTP requests into a subject and a fruster message which are posted on the message bus so inbound services may handle the request.

The message model itself allows any valid JSON to be sent but wraps the payload inside a predefined message model that includes additional meta data.

Message bus

The message bus is the backbone to which all services connect and is used to communicate with each other. Fruster uses NATS message bus, which is a lightweight and high performing message bus.

In the fruster the message bus handles services discovery, load balancing and message delivery.

A service within Fruster defines which subjects to subscribe to. When any request is sent that matches the subject the service will handle the request and (in most cases) return a response.

A lot of the ground work to interact with the message bus is wrapped into the library fruster-bus.

Message model

Apart from the data attribute which holds the payload, a fruster message includes meta data to answer the following:

  • Logging
    • Which service sent this message?
    • Which message sequence does this message belong to?
    • Which transaction does this message belong to?
  • User identification
    • Who is the logged in user and which scopes does she have?
  • Optional HTTP meta data (only available for HTTP requests and responses)
    • HTTP headers
    • Query params
    • Path params
PropertyTypeRequiredDescription
reqIduuidYesIs generated and set by the initiator of a request sequence (usually the API gateway) and passed on to all subsequent messages. Used for logging to group all messages in a message sequence.
transactionIduuidYesId of transaction (request + response = transaction). Used for logging.
userobject-Logged in user, only set if a JWT token exists and has been decrypted.
fromobjectYes*Name and instance id of service that sent the message.
dataany-Payload of message.
statusnumberYes, for responsesHTTP status code of response.
errorobjectYes, if error responseSee below for error properties.
error.iduuidYes, if error responseA unique identifier for this particular occurrence of the problem
error.codestringYes, if error responseError code that describes the error, for example BAD_REQUESTS
error.titlestring-Human friendly text describing the error. Should be kept same for all instances of this error.
error.detailstring-Human friendly text describing the error with details that relates to this particular instance of the error.
methodstringYes, if HTTP reqHTTP method of request. Only present in HTTP messages.
pathstringYes, if HTTP reqHTTP path. Only present in HTTP request messages.
headersobject-HTTP headers of request/response, if any. Only present in HTTP messages.
queryobject-HTTP query params, if any. Only present in HTTP request messages.
paramsobject-HTTP path params, if any. Only present in HTTP request messages. Is parsed and set by API Gateway.

Example: HTTP request

{
  "reqId": "bc42858e-0346-4c5d-8481-084ff9a0f4d1",
  "data": {
    "foo": "bar"
  },
  "method": "POST",
  "path": "/foo/123",
  "params": {
    "id": "123"
  },
  "transactionId": "237866da-3a46-4fa1-9f64-8eda0b1199de"
}

Example: Error response

{
  "reqId": "bc42858e-0346-4c5d-8481-084ff9a0f4d1",
  "status": 400,
  "error": {
    "id": "28420b97-9ccf-45de-8314-3505df5c3e17",
    "code": "BAD_REQUEST",
    "title": "Bad request"
  },
  "transactionId": "237866da-3a46-4fa1-9f64-8eda0b1199de"
}

Subjects

Subject is the address a message is published to similar to an URL path. It is an alphanumeric string with dot . delimiters where the dot is used to define hierarchies.

A subject can be subscribed on by exact match (i.e. user.create) or with wildcards * or > (i.e. user.*). Check out NATS protocol documentation for details.

HTTP message subject

The API Gateway will translate HTTP requests and responses into bus messages. The translation is made on format:

http.{GET|POST|PUT|DELETE}.{path with dot instead of slash}

Example:

GET /user => http.get.user