/bauta.js

Bauta.js is an add-on for your Node.js applications such as Express.js or Fastify.

Primary LanguageTypeScriptOtherNOASSERTION

Bauta.js

What is Bauta.js

Bauta.js is an add-on for your Node.js applications such as Express.js or Fastify. Bauta.js improves the developer experience enriching your application architecture and encouraging an API design-first mindset. The main features Bauta.js provides are:

  • Express.js plugin.
  • Fastify plugin.
  • Resolvers.
  • Pipelines and Steps functions.
  • Decorators.
  • Request/Response validation.
  • Built-in OpenAPI explorer.
  • API versioning.
  • Datasource Providers.
  • Built-in logging system.
  • Written in TypeScript.

Bauta.js and developer experience

If you want an overview of what bauta.js is about from a developer experience point of view, check the developer experience section.

Quick start

To get started with Bauta.js, we recommend using one of the framework's plugins it exposes. For example, if you feel comfortable writing your Node.js applications using Express.js, you should use the Bauta.js Express plugin. However, we recommend the usage of the Bauta.js Fastify plugin.

First, get Bauta.js with npm and the required dependencies:

npm i fastify@4 @axa/bautajs-core @axa/bautajs-fastify

Then create server.js and add the following content:

const fastify = require('fastify')({ logger: true });
const { resolver } = require('@axa/bautajs-core');
const { bautajsFastify } = require('@axa/bautajs-fastify');

// You can use your own OpenAPI specifications ;)
const apiDefinition = {
  openapi: '3.0.0',
  info: {
    version: 'v1',
    title: 'Bauta.js quick start'
  },
  paths: {
    '/greetings': {
      get: {
        operationId: 'getGrettings',
        responses: {
          200: {
            description: 'say hello world :)',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    hello: {
                      type: 'string'
                    },
                    name: {
                      type: 'string'
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
};

fastify.register(bautajsFastify, {
  apiDefinition,
  resolvers: [
    resolver(operations => {
      operations.getGrettings.setup(() => ({ hello: 'world' }));
    })
  ],
  apiBasePath: '/api'
});

// Run the server!
const start = async () => {
  try {
    await fastify.listen(3000)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

Launch the server:

node server.js

You can test it with curl:

curl http://localhost:3000/api/grettings

=> { hello: 'world' }

Features

Resolvers

Bauta.js Core creates every operation described on the OpenAPI schema as a route when the plugin is initialized. The resolvers are where you specify the logic of every route/operation. A resolver can be an async function too.

We recommend writing the resolvers in a separate Node.js module using a specific name pattern used on the Bauta.js plugin initialization as a glob. For example, we could have our resolvers on files named like greeting-resolver.js and then initialize the Bauta.js instance like the following:

// server.js
...

fastify.register(bautajsFastify, {
  apiDefinition,
  resolversPath: '*-resolver.js',
  apiBasePath: '/api'
});

...
// greeting-resolver.js
const { resolver } = require('@axa/bautajs-core');

module.exports = resolver(operations => {
  operations.getGrettings.setup(() => ({ hello: 'world' }));
})
//

Pipelines

Bauta.js provides a set of decorators to ease writing the logic of your endpoint's resolvers. One of the most exciting decorators is pipe. It allows expressing the logic as a flow of data that follows a pipeline. It helps to separate the logic on small reusable and testable functions called steps. A step function can be async.

const { pipe, resolver } = require('@axa/bautajs-core');

module.exports = resolver(operations => {
  operations.getGrettings.setup(
    pipe(
      () => ({ hello: 'world' }),
      (previous) => ({...previous, name: 'pepe'})
    );
})

Bauta.js passes to every Step function of a Pipeline a Context (ctx) object, unique by request, including a logger, the request's id, and data transmitted through all the pipeline steps t. Check additional information about the Bauta.js Context on its dedicated documentation page.

To understand better about Step functions and Pipelines your can read the following documentation page.

Decorators

Bauta.js has a set of valuable decorators that you can use to build your resolvers pipelines.

Request and response validation

Bauta.js validates, based on the OpenAPI schema provided, the request input by default and could validate the response of your endpoints if you enabled it. For further details, take a look to the following documentation.

Built-in OpenAPI explorer (swagger)

Using Bauta.js you are ready from the beginning to share your OpenAPI documentation exposed to the /explorer endpoint by default.

With the bautajs-fastify plugin you will have the capability of having multiple openAPI exposed if you have multiple version exposed of your API (see API versioning section). In this case the explorer will be exposed with the prefix of every Bauta.js instance, i.e. /v1/explorer.

API versioning

Bauta.js supports API versioning helping with the management of breaking changes. You only need to implement the new behaviour for the changed endpoints. The endpoints that remain unaltered in the new version can be inherited by higher API versions reusing the implementation on the previous API version. Get more details about how Bauta.js allow API versioning here.

Request cancellation

Bauta.js is able to cancel any operation pipeline if the request is aborted or cancelled by the requester. For more details, check its documentation page.

Datasources providers

Bauta.js was born with the aim of implementing Node.js APIs that behaves like middleware to other third parties APIs. With that premise in mind, Bauta.js has the concept of HTTP request datasources. A Bauta.js request datasource is an abstraction of an HTTP(S) request to a third-party API. It's based on the request library got and Bauta.js enrich its behaviour by adding useful logs and HTTP(S) proxy support and request cancellation. A datasource can be used as a step function inside any Bauta.js pipeline. Check more examples of datasources on its specific documentation.

Builtin logging system

The logging capability is key to troubleshooting and operates successfully our APIs on production. Using pino as the default logger, Bauta.js logs useful information in every request: request identifier, endpoint signature, response time, datasources requests information, and so on. Check here for additional information.

Written with TypeScript

Bauta.js is written using TypesScript. Shipped with the typings definitions to improve the developer experience using IntelliSense on your favourite IDE.

Guides

Benchmark

See Benchmark.

Contributing

You can read the guide of how to contribute at Contributing.

Bauta.js is a monorepo containing the following list of packages:

Code of Conduct

You can read the Code of Conduct at Code of Conduct.

Legal Notice

Copyright (c) AXA Group. All rights reserved. Licensed under the MIT License.

Third party dependencies licenses

Production

Development