SkillAgentSearch skills...

Scribano

Automatically build AsyncAPI documentation for your RabbitMQ messages

Install / Use

/learn @uesteibar/Scribano

README

Scribano

Codacy Badge CircleCI

Builds an asyncapi documentation for your microservices communicating through rabbitmq.

It listens to all published amqp messages and keeps an updated asyncapi compliant documentation served at /asyncapi.

Sample configuration can be found here.

How does it work?

Scribano will subscribe to a set of configured RabbitMQ exchanges, and will start consuming events from there.

When a message is consumed, scribano will infer a structure for the content. For example, after consuming a message on the some.key routing key with the following payload:

{
  "name": "infer type",
  "age": 27,
  "grade": 9.5,
  "canDrive": false,
  "birthDate": "1991-08-29",
  "lastLogin": "2015-06-10T13:23:30-08:00",
  "address": null,
  "emptyHash": {},
  "fines": [],
  "emptyHashes": [{}],
  "matrix": [
    [1, 2, 3],
    [3, 2, 1]
  ],
  "friends": [
    { "name": "pepe" },
    { "name": "gotera" }
  ],
  "car": {
    "brand": "mercedes"
  }
}

The following spec will be served on /asyncapi

{
  "asyncapi": "1.0.0",
  "info": {
    "title": "",
    "version": ""
  },
  "topics": {
    "some.key": {
      "publish": {
        "$ref": "#/components/messages/SomeKey"
      },
      "x-exchange": "/my-exchange"
    }
  },
  "components": {
    "messages": {
      "SomeKey": {
        "payload": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string"
            },
            "age": {
              "type": "integer"
            },
            "grade": {
              "type": "number"
            },
            "birthDate": {
              "type": "string",
              "format": "date"
            },
            "lastLogin": {
              "type": "string",
              "format": "date-time"
            },
            "address": {
              "type": "string"
            },
            "emptyHash": {
              "type": "object"
            },
            "fines": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "emptyHashes": {
              "type": "array",
              "items": {
                "type": "object"
              }
            },
            "matrix": {
              "type": "array",
              "items": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              }
            },
            "friends": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "birthDate": {
                    "type": "string",
                    "format": "date"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              }
            },
            "car": {
              "type": "object",
              "properties": {
                "brand": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}

Type inference

| value | inferred type | format | notes | |:---------------------------:|:-------------:|:---------:|:----------------------------------------------------------------------:| | "some string" | string | | | | "1991-08-29" | string | date | Format must match exactly, otherwise it is considered a regular string | | "2015-06-10T13:23:30-08:00" | string | date-time | Format must match exactly, otherwise it is considered a regular string | | true / false | boolean | | | | [...] | array | | Type for the array values is inferred by checking on the first element | | {...} | object | | Types for the fields inside the object are checked recursively | | null | string | | |

Optional fields

Fields are set as optional using the custom x-optional: true attribute.

When a fields is received in a message and then not received in a subsequent message, it is considered optional as the presence of that field cannot be guaranteed.

When a field is received in a message and was never previously received, it is also considered optional.

Running locally

Install dependencies

go mod download

Load environmental variables

source .env.dev
go run main.go -f fixtures/test/yaml_config.yml

You can also fetch the configuration from a url

go run main.go -u https://raw.githubusercontent.com/uesteibar/scribano/master/fixtures/test/yaml_config.yml

Running on docker

docker run -e PG_URL='postgresql://postgres:postgres@localhost:5433/asyncapi' uesteibar/scribano ./scribano -u https://raw.githubusercontent.com/uesteibar/scribano/master/fixtures/test/yaml_config.yml

Running tests

Start the rabbitmq server

docker-compose up -d

Run the tests

make test
View on GitHub
GitHub Stars9
CategoryDevelopment
Updated3y ago
Forks1

Languages

Go

Security Score

75/100

Audited on Mar 18, 2023

No findings