Self-documented microservices (ArangoDB + swagger)

    Maintaining documentation for microservices up to date still requires the utmost discipline in the development, well, and large labor costs. A very reasonable approach to creating documentation is, for example, GraphQL, where documentation is inextricably linked with the program code and this guarantees 100% compliance with the documentation and the services being documented. However, the unusual approach of GraphQL for developers accustomed to the REST-API still makes it difficult to promote this technology in practical application development. Here you can also recall SOAP, which has long solved the problem of matching documentation and services, but due to over-complication did not take root among the masses of developers.

    I would like to find such a stack of technologies for the development of microservices, which ensured the same self-documenting of the program code when developing the "traditional" REST-API microservices. And he, as it turned out, already exists.

    We define the actors and performers who will be involved in our small example.

    ArangoDB is a hybrid, document-based + graph-oriented database.

    UPD. A more detailed acquaintance with this database became an occasion for another disappointment. As it turned out, after the database has exceeded the non-commitit limit, which is limited by free RAM, the base starts to slow down, it just stops along with the server. At the same time, they made tentative assumptions that the transition to new storage engines would work better, which had not yet been confirmed.

    Foxx is a microservice framework built into the ArangoDB database. It runs on a JavaScript engine, which (unlike nodejs) can simultaneously run in an unlimited number of parallel threads (not blocking each other), as a result of which there is no need for promise / than / canch and async / await constructions. Unlike mongodb, in which it is not recommended to abuse server procedures, and relational databases, in which stored procedures are also used carefully and certainly do not interact through the REST-API with clients (browsers, mobile applications, etc.) - microservice framework Foxx was developed just for the development of microservices that communicate directly via the http protocol with clients.

    Swagger is an open source software environment supported by a large ecosystem of tools that helps developers develop, create, document, and consume RESTful web services. Although most users identify Swagger with the Swagger UI, the Swagger toolkit includes support for automatic documentation, code generation, and test case generation.

    The fact that Swagger includes supporting code generation is a situation that opposes the one that I would like to receive - when the code supports the generation of documentation. What offers us ArangoDB + Foxx just includes the opposite option. When on the code of microservices the scheme for Swagger is generated. However, now this can be seen for yourself having done a minimum of work.

    You must have ArangoDB installed to take further action.

    1. Enter the admin area and select the item to create a new microservice Services-> Add service-> New.
    2. We fill in the required details in the opened form. In the field “Document Collections” we add the name of the collection of documents that will be created when the microservice is expanded. For example, cats.
    3. We click on the install button, enter in the url field, to which the microservice will be attached.

    When installing microservice, for each collection from the field “Document Collections” (see p.2), routes will be created that implement CRUD operations using the POST, GET, PUT and DELETE methods. However, these are only methods that can be changed, deleted, and added new ones. We chose one collection when creating microservices (cats), although we could not do this, but add everything later manually.

    Now our cats collection has routes for CRUD operations, and we can start calling these routes from the database admin panel by selecting the API tab (Services -> [Microservice name] -> API). This tab contains the familiar Swagger interface. It is also possible to publish the Swagger interface on an external route accessible not only through the admin area, but like a regular URL.

    If you try to add a document to the cats collection using the POST {"name": "Tom"} method, you will get an error status. Because we have nowhere defined the name field. Therefore, we will continue to work with the admin ArangoDB.

    4. For more convenient development, ArangoDB has a Development mode, which is enabled on the Settings tab (Services -> [Microservice name] -> Settings-Set development)

    Now you can change the worldservice code and immediately observe the result (without additional deployment). The directory in which the microservice program code is located can be found in the admin panel on the Info tab (Services -> [Microservice name] -> Info).

    Let's see how the defined POST route looks.

    'use strict';
    const dd = require('dedent');
    const joi = require('joi');
    const httpError = require('http-errors');
    const status = require('statuses');
    const errors = require('@arangodb').errors;
    const createRouter = require('@arangodb/foxx/router');
    const Cat = require('../models/cat');
    const cats = module.context.collection('cats');
    const keySchema = joi.string().required()
    .description('The key of the cat');
    const HTTP_NOT_FOUND = status('not found');
    const HTTP_CONFLICT = status('conflict');
    const router = createRouter();
    module.exports = router;
    router.tag('cat'); (req, res) {
      const cat = req.body;
      let meta;
      try {
        meta =;
      } catch (e) {
        if (e.isArangoError && e.errorNum === ARANGO_DUPLICATE) {
          throw httpError(HTTP_CONFLICT, e.message);
        throw e;
      Object.assign(cat, meta);
      res.set('location', req.makeAbsolute(
        req.reverse('detail', {key: cat._key})
    }, 'create')
    .body(Cat, 'The cat to create.')
    .response(201, Cat, 'The created cat.')
    .error(HTTP_CONFLICT, 'The cat already exists.')
    .summary('Create a new cat')
      Creates a new cat from the request body and
      returns the saved document.

    Both validation and documentation are based on the use of the object schema. Let's make some small changes to it by adding the name field:

    'use strict';
    const _ = require('lodash');
    const joi = require('joi');
    module.exports = {
      schema: {
        // Describe the attributes with joi here
        _key: joi.string(),
        name: joi.string().description('cat`s name'), // добавили новое поле
      forClient(obj) {
        // Implement outgoing transformations here
        obj = _.omit(obj, ['_id', '_rev', '_oldRev']);
        return obj;
      fromClient(obj) {
        // Implement incoming transformations herereturn obj;

    Turning to the API zakadku, you can make sure that the scheme has changed and now an object with the name field can be added to the cats collection.
    November 12, 2018.

    Also popular now: