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:
If you want an overview of what bauta.js is about from a developer experience point of view, check the developer experience section.
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' }
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' }));
})
//
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.
Bauta.js has a set of valuable decorators that you can use to build your resolvers pipelines.
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.
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
.
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.
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.
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.
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.
Bauta.js is written using TypesScript. Shipped with the typings definitions to improve the developer experience using IntelliSense on your favourite IDE.
See Benchmark.
You can read the guide of how to contribute at Contributing.
Bauta.js is a monorepo containing the following list of packages:
You can read the Code of Conduct at Code of Conduct.
Copyright (c) AXA Group. All rights reserved. Licensed under the MIT License.