diff --git a/docs/api-versioning.md b/docs/api-versioning.md index c813b53..1b59321 100644 --- a/docs/api-versioning.md +++ b/docs/api-versioning.md @@ -1,46 +1,42 @@ # API versioning -Bauta.js has API versioning out of the box to version your API operations. +## Context -As Bauta.js is loading all files under ./resolvers file by default, it's recommended to follow the next folder structure, remember you can change this default path by other one. +By API versioning we mean the fact that we can have a running server with two different versions of the same endpoint. -```console -- resolvers - -- v1 - -- cats-resolver.js - -- v2 - -- cats-resolver.js -``` +Let's assume that initially we have a service without any versioning whatsoever. This means that we have the following set of components: -```js -// v1/cats-resolver.js -const { resolver } = require('@axa/bautajs-core'); -module.exports = resolver((operations) => { - operations.findCat.setup((_, ctx) => { - return { - name: 'toto' - } - }); -}) -``` +- a swagger api definition with certain routes and operations defined +- a set of resolvers that implement those operations +- a bauta service that loads and exposes both swagger and resolvers. -```js -// v2/cats-resolver.js -const { resolver } = require('@axa/bautajs-core'); -module.exports = resolver((operations) => { - operations.findCatV2.setup((_, ctx) => { - return { - idV2: 'toto' - } - }); -}) -``` +In the context of bauta, for versioning we mean the capability to provide a subset of those api's in a different prefixed route with a different swagger. + +This means that after versioning is applied we have the following: + +- the original swagger api definition with certain routes and operations defined, some of them marked as deprecated +- the original set of resolvers that implement those operations +- a new swagger with certain new routes and operations defined in a different way +- a new set of resolvers that implement these new operations +- a bauta service that loads and exposes both swagger and resolvers, for the original and for the new services. + + +## Configuration for versioning -This is an example of API definitions for two API versions: +For versioning to work there are three parts that **must** be configured in order to work. + +### 1. Swagger API definition + +:exclamation: You **must** declare any existing route that you want to use as a new version as ``deprecated``. :exclamation: + +This is required to make sure that bautaJs does not overwrite the new version with the original route implementation. + +Below there is an example of API definitions for two API versions (note: you may use two different swaggers and load each one of them separatedly): ```json // api-definitions.json - [ { +[ + { "openapi": "3.0.0", "info": { "description": "A new API", @@ -49,30 +45,31 @@ This is an example of API definitions for two API versions: }, "servers": [ { - "url":"/v1/api/" - } + "url": "/v1/api/" + } ], "paths": { "/cats": { - "get":{ - "operationId":"findCat", + "get": { + "operationId": "findCat", + "deprecated": true, // <-- MUST mark it as deprecated if you want to use new version of the same route "responses": { "200": { "description": "Miau!", "content": { "application/json": { "schema": { - "properties": { - "name": { - "type": "string" + "properties": { + "name": { + "type": "string" } } } } } + } } } - } } } }, @@ -85,36 +82,100 @@ This is an example of API definitions for two API versions: }, "servers": [ { - "url":"/v2/api/" - } + "url": "/v2/api/" + } ], "paths": { "/cats": { - "get":{ - "operationId":"findCatV2", + "get": { + "operationId": "findCatV2", "responses": { "200": { "description": "Miaw!", "content": { "application/json": { - "schema": { - "properties": { - "name": { - "type": "string" - } + "schema": { + "properties": { + "petName": { // Breaking change: petName instead of name in v1 + "type": "string" } } + } } } + } } } - } } } - }] + } +] +``` + + + +#### Deprecation programmaticaly + +Bautajs supports the deprecation by code with the resolver method `setAsDeprecated`. + +```js +const { resolver } = require('@axa/bautajs-core'); +// my-resolver.js +module.exports = resolver(operations) => { + operations.findCats.setAsDeprecated().setup(() => 'result'); +} +``` + +While you may use this in a pinch we strongly suggest that you favour the deprecation of services at swagger level whenever possible. + +In any case the deprecation of routes that you are versioning, either by swagger or programmatically, **is mandatory**. + + +### 2. Resolver resolution + + +Bauta.js has API versioning out of the box to version your API operations. + +As Bauta.js is loading all files under ./resolvers file by default, it's recommended to follow the next folder structure, remember you can change this default path by other one. + +```console +- resolvers + -- v1 + -- cats-resolver.js + -- v2 + -- cats-resolver.js ``` -### Example using Bauta.js core without a Node.js framework plugin + +```js +// resolvers/v1/cats-resolver.js +const { resolver } = require('@axa/bautajs-core'); +module.exports = resolver((operations) => { + operations.findCat.setup((_, ctx) => { + return { + name: 'toto' + } + }); +}) +``` + +```js +// resolvers/v2/cats-resolver.js +const { resolver } = require('@axa/bautajs-core'); +module.exports = resolver((operations) => { + operations.findCatV2.setup((_, ctx) => { + return { + petName: 'toto' + } + }); +}) +``` + +### 3. BautaJS instantiation of both API versions + +When you want to apply versioning, you have to modify slightly the way that bautaJs starts up to clearly configure what is considered the old version of your service endpoints and what is considered the latest version. + +#### Example using Bauta.js core without a Node.js framework plugin Now we need to specify a `bautaJS` instance per API swagger version. @@ -126,11 +187,13 @@ const apiDefinition = require('./api-definitions.json'); const bautajsV1 = new BautaJS({ apiDefinition: apiDefinitions[0], + resolversPath: './resolvers/v1/cats-resolvers.js', prefix: '/v1/', apiBasePath: '/api/' }); -const bautajsV2 = new BautaJS({ +const bautajsV2 = new BautaJS({ apiDefinition: apiDefinitions[1], + resolversPath: './resolvers/v2/cats-resolvers.js', prefix: '/v2/', apiBasePath: '/api/' }); @@ -146,7 +209,7 @@ const bautajsV2 = new BautaJS({ const res1 = await bautajsV2.operations.findCat.run(); // result: name: 'toto' const res2 = await bautajsV2.operations.findCatV2.run(); - // result: idV2: 'toto' + // result: petName: 'toto' console.log(res1, res2); })() @@ -158,9 +221,10 @@ In this example the `findCat` from v1 instance will be inherited to the v2 insta Calling `inheritOperationsFrom` after bootstrap the instance is not possible and will always throw an error. This behaviour is intended since api schema is resolved on bootstrap time so if the instance is already bootstrapped and `inheritOperationsFrom` is called after this could lead to unexpected behaviour of your API. -### Example using Bauta.js with a @axa/bautajs-fastify plugin -#### Creating the Bauta.js instances and setting up the inheritance outside the plugin +#### Example using Bauta.js with a @axa/bautajs-fastify plugin + +##### Creating the Bauta.js instances and setting up the inheritance outside the plugin ```js const { BautaJS } = require('@axa/bautajs-core'); @@ -170,24 +234,26 @@ const apiDefinition = require('./api-definitions.json'); const bautajsV1 = new BautaJS({ apiDefinition: apiDefinitions[0], - prefix: '/v1/', - apiBasePath: '/api/' + resolversPath: './resolvers/v1/cats-resolvers.js', }); const bautajsV2 = new BautaJS({ apiDefinition: apiDefinitions[1], - prefix: '/v2/', - apiBasePath: '/api/' + resolversPath: './resolvers/v2/cats-resolvers.js', }); (async () => { await fastifyInstance .register(bautajsFastify, { - bautajsInstance: bautajsV1 + bautajsInstance: bautajsV1, + prefix: '/v1/', + apiBasePath: '/api/' }) .after(() => { bautajsV2.inheritOperationsFrom(bautajsV1); fastifyInstance.register(bautajsFastify, { - bautajsInstance: bautajsV2 + bautajsInstance: bautajsV2, + prefix: '/v2/', + apiBasePath: '/api/' }); }); @@ -195,13 +261,13 @@ const bautajsV2 = new BautaJS({ const res1 = await bautajsV2.operations.findCat.run(); // result: name: 'toto' const res2 = await bautajsV2.operations.findCatV2.run(); - // result: idV2: 'toto' + // result: petName: 'toto' console.log(res1, res2); })() ``` -#### Creating the Bauta.js instances and setting up the inheritance with the plugin option 'inheritOperationsFrom' +##### Creating the Bauta.js instances and setting up the inheritance with the plugin option 'inheritOperationsFrom' ```js const { BautaJS } = require('@axa/bautajs-core'); @@ -211,24 +277,27 @@ const apiDefinition = require('./api-definitions.json'); const bautajsV1 = new BautaJS({ apiDefinition: apiDefinitions[0], - prefix: '/v1/', - apiBasePath: '/api/' + resolversPath: './resolvers/v1/cats-resolvers.js' }); + const bautajsV2 = new BautaJS({ apiDefinition: apiDefinitions[1], - prefix: '/v2/', - apiBasePath: '/api/' + resolversPath: './resolvers/v2/cats-resolvers.js' }); (async () => { await fastifyInstance .register(bautajsFastify, { - bautajsInstance: bautajsV1 + bautajsInstance: bautajsV1, + prefix: '/v1/', + apiBasePath: '/api/' }) .after(() => { fastifyInstance.register(bautajsFastify, { bautajsInstance: bautajsV2, - inheritOperationsFrom: bautajsV1 + inheritOperationsFrom: bautajsV1, + prefix: '/v2/', + apiBasePath: '/api/' }); }); @@ -236,13 +305,13 @@ const bautajsV2 = new BautaJS({ const res1 = await bautajsV2.operations.findCat.run(); // result: name: 'toto' const res2 = await bautajsV2.operations.findCatV2.run(); - // result: idV2: 'toto' + // result: petName: 'toto' console.log(res1, res2); })() ``` -#### Creating only the parent Bauta.js instance and setting up the inheritance with the plugin option 'inheritOperationsFrom' +##### Creating only the parent Bauta.js instance and setting up the inheritance with the plugin option 'inheritOperationsFrom' ```js const { BautaJS } = require('@axa/bautajs-core'); @@ -252,20 +321,22 @@ const apiDefinition = require('./api-definitions.json'); const bautajsV1 = new BautaJS({ apiDefinition: apiDefinitions[0], - prefix: '/v1/', - apiBasePath: '/api/' + resolversPath: './resolvers/v1/cats-resolvers.js' }); (async () => { await fastifyInstance .register(bautajsFastify, { - bautajsInstance: bautajsV1 + bautajsInstance: bautajsV1, + prefix: '/v1/', + apiBasePath: '/api/' }) .after(() => { - fastifyInstance.register(bautajsFastify, { + fastifyInstance.register(bautajsFastify, { apiDefinition: apiDefinitions[1], + resolversPath: './resolvers/v2/cats-resolvers.js', prefix: '/v2/', - apiBasePath: '/api/' + apiBasePath: '/api/', inheritOperationsFrom: bautajsV1 }); }); @@ -274,78 +345,14 @@ const bautajsV1 = new BautaJS({ const res1 = await bautajsV2.operations.findCat.run(); // result: name: 'toto' const res2 = await bautajsV2.operations.findCatV2.run(); - // result: idV2: 'toto' + // result: petName: 'toto' console.log(res1, res2); })() ``` -### Example using Bauta.js with a @axa/bautajs-express plugin - -TBD +Note about the examples: these are orientative examples, if you want to use them in a real case scenario, remember that you need +to start up the server accordingly (for instance, in `fastify` you have to listen to the plugin instance you have created and registered). -## Deprecate an operation -A deprecated operation means that on call `inheritOperationsFrom` method that operation won't be `cloned` to the new instance. - -#### Deprecation programmaticaly - -```js -const { resolver } = require('@axa/bautajs-core'); -// my-resolver.js -module.exports = resolver(operations) => { - operations.findCats.setAsDeprecated().setup(() => 'result'); -} -``` - -#### Deprecation by OpenAPI swagger schema - -```json -// api-definitions.json -[ - { - "openapi": "3.0.0", - "apiVersion": "1.0", - "info": { - "description": "A new API", - "version": "v1", - "title": "CORE API" - }, - "servers": [ - { - "url":"/v1/api/" - } - ], - "paths": { - "/cats": { - "get":{ - "operationId":"findCat", - "deprecated": true - } - } - } - }, - { - "openapi": "3.0.0", - "apiVersion": "2.0", - "info": { - "description": "A new API", - "version": "v2", - "title": "CORE API" - }, - "servers": [ - { - "url":"/v1/api/" - } - ], - "paths": { - "/cats": { - "get":{ - "operationId":"findCat" - } - } - } - } -] -``` diff --git a/packages/bautajs-fastify-versioning-example/README.md b/packages/bautajs-fastify-versioning-example/README.md new file mode 100644 index 0000000..68bf23d --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/README.md @@ -0,0 +1,43 @@ +# bautajs-fastify-versioning-example + +- This API example intends to show how you can manage versioning with bautajs-fastify. +- This project example purpose is to showcase main features using simple examples. +- This project example **does not** intend to show good practices using Node.js or security practices at all. Please be sure you follow security good practices on your Node.js API (i.e. adding [helmet](@fastify/helmet)). + +## How to start + +- It is recommented that you are using node v18. +- `npm install` from the root project of the monorepo +- enter into `packages/bautajs-fastify-versioning-example` folder + +## Brief explanation of the different examples + +We have a set of three services: + +- `v1` + - `cats` --> endpoint marked as `deprecated`. This service returns name, communication and breed + - `dogs` --> This service returns name, communication and breed +- `v2` + - `cats` --> latest version of the endpoint. This service returns petName, communication and favouriteAction + + +## An example of each initialization method + +You can run npm start for each one of the scripts: + +- ``npm run start``: Uses default port 8080. Basic example without any versioning. Only v1 endpoints are exposed. +- ``start:external``: Configures the versioning inheritance outside the plugin. +- ``start:plugin``: Configures the versioning inheritance with the plugin option 'inheritOperationsFrom' and instantiates the two instances of bautaJs (the original and the new version). +- ``start:parent``: Configures the versioning inheritance instantiating only the parent bautaJs instance and uses the plugin option 'inheritOperationsFrom' to add the new version endpoints. + + +This is only a showcase of how the versioning works. For details you should check [versioning](https://github.com/axa-group/bauta.js/blob/main/docs/api-versioning.md). + + +## Third party dependencies licenses + +### Production + - [@axa/bautajs-core@3.0.0](https://github.com/axa-group/bauta.js) - MIT* + - [@axa/bautajs-datasource-rest@3.0.0](https://github.com/axa-group/bauta.js) - MIT* + - [@axa/bautajs-fastify@3.0.0](https://github.com/axa-group/bauta.js) - MIT* + - [fastify@4.8.1](https://github.com/fastify/fastify) - MIT diff --git a/packages/bautajs-fastify-versioning-example/api-definitions-v1.json b/packages/bautajs-fastify-versioning-example/api-definitions-v1.json new file mode 100644 index 0000000..0c7f4fb --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/api-definitions-v1.json @@ -0,0 +1,70 @@ +{ + "openapi": "3.0.0", + "info": { + "description": "A new API", + "version": "v1", + "title": "Cats API" + }, + "servers": [ + { + "url": "/v1/api/" + } + ], + "paths": { + "/cats": { + "get": { + "operationId": "findCat", + "deprecated": true, + "responses": { + "200": { + "description": "Miau!", + "content": { + "application/json": { + "schema": { + "properties": { + "name": { + "type": "string" + }, + "communication": { + "type": "string" + }, + "breed": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/dogs": { + "get": { + "operationId": "findDog", + "responses": { + "200": { + "description": "Woof!", + "content": { + "application/json": { + "schema": { + "properties": { + "name": { + "type": "string" + }, + "communication": { + "type": "string" + }, + "breed": { + "type": "string" + } + } + } + } + } + } + } + } + } + } +} diff --git a/packages/bautajs-fastify-versioning-example/api-definitions-v2.json b/packages/bautajs-fastify-versioning-example/api-definitions-v2.json new file mode 100644 index 0000000..189203a --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/api-definitions-v2.json @@ -0,0 +1,42 @@ +{ + "openapi": "3.0.0", + "info": { + "description": "A new API", + "version": "v2", + "title": "Cats API" + }, + "servers": [ + { + "url": "/v2/api/" + } + ], + "paths": { + "/cats": { + "get": { + "operationId": "findCatV2", + "responses": { + "200": { + "description": "Miaw!", + "content": { + "application/json": { + "schema": { + "properties": { + "petName": { + "type": "string" + }, + "communication": { + "type": "string" + }, + "favouriteAction": { + "type": "string" + } + } + } + } + } + } + } + } + } + } +} diff --git a/packages/bautajs-fastify-versioning-example/package.json b/packages/bautajs-fastify-versioning-example/package.json new file mode 100644 index 0000000..f8f4751 --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/package.json @@ -0,0 +1,29 @@ +{ + "name": "@axa/bautajs-fastify-versioning-example", + "version": "1.0.0", + "description": "A bautaJS example of versioning in fastify", + "main": "./server-without-versioning.js", + "scripts": { + "start": "LOG_LEVEL=info DEBUG=bautajs* node ./server-without-versioning.js", + "start:parent": "LOG_LEVEL=info DEBUG=bautajs* node ./versioning-only-parent.js", + "start:plugin": "LOG_LEVEL=info DEBUG=bautajs* node ./versioning-plugin-inherits.js", + "start:external": "LOG_LEVEL=info DEBUG=bautajs* node ./versioning-external-inherits.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/axa-group/bauta.js" + }, + "private": true, + "keywords": [ + "bautajs", + "fastify", + "middleware" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@axa/bautajs-core": "^3.1.0", + "@axa/bautajs-datasource-rest": "^3.1.0", + "@axa/bautajs-fastify": "^3.1.0", + "fastify": "^4.15.0" + } +} diff --git a/packages/bautajs-fastify-versioning-example/server-without-versioning.js b/packages/bautajs-fastify-versioning-example/server-without-versioning.js new file mode 100644 index 0000000..40e0356 --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/server-without-versioning.js @@ -0,0 +1,37 @@ +const fastify = require('fastify')({ logger: true }); + +const { bautajsFastify } = require('@axa/bautajs-fastify'); +const { BautaJS } = require('@axa/bautajs-core'); + +const apiDefinitionsV1 = require('./api-definitions-v1.json'); + +const bautaJsV1 = new BautaJS({ + apiDefinition: apiDefinitionsV1, + resolversPath: './server/**/resolvers*.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +(async () => { + fastify.register(bautajsFastify, { + bautajsInstance: bautaJsV1, + prefix: '/v1/', + apiBasePath: '/api/' + }); + + fastify.listen( + { + host: '0.0.0.0', + port: 8080 + }, + err => { + if (err) throw err; + fastify.log.info('Server listening on localhost:', fastify.server.address().port); + } + ); +})(); diff --git a/packages/bautajs-fastify-versioning-example/server/v1/resolvers.js b/packages/bautajs-fastify-versioning-example/server/v1/resolvers.js new file mode 100644 index 0000000..354971c --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/server/v1/resolvers.js @@ -0,0 +1,22 @@ +const { pipe, resolver, step } = require('@axa/bautajs-core'); + +const getCatStep = step(() => { + return { + name: 'Grey', + communication: 'Meow', + breed: 'all cats are the same' + }; +}); + +const getDogStep = step(() => { + return { + name: 'Milu', + communication: 'Woof', + breed: 'fox-terrier' + }; +}); + +module.exports = resolver(operations => { + operations.findCat.validateRequest(true).validateResponse(true).setup(pipe(getCatStep)); + operations.findDog.validateRequest(true).validateResponse(true).setup(pipe(getDogStep)); +}); diff --git a/packages/bautajs-fastify-versioning-example/server/v2/resolvers.js b/packages/bautajs-fastify-versioning-example/server/v2/resolvers.js new file mode 100644 index 0000000..116cf3b --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/server/v2/resolvers.js @@ -0,0 +1,21 @@ +const { pipe, resolver, step } = require('@axa/bautajs-core'); + +const getCatStep = step(() => { + return { + petName: 'Blondie', + communication: 'Meow', + favouriteAction: 'Purr' + }; +}); + +module.exports = resolver(operations => { + operations.findCatV2 + .validateRequest(true) + .validateResponse(true) + .setup( + pipe(getCatStep, prev => { + console.log('mierda mia', prev); + return prev; + }) + ); +}); diff --git a/packages/bautajs-fastify-versioning-example/versioning-external-inherits.js b/packages/bautajs-fastify-versioning-example/versioning-external-inherits.js new file mode 100644 index 0000000..bf64e3e --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/versioning-external-inherits.js @@ -0,0 +1,60 @@ +const fastify = require('fastify')({ logger: true }); + +const { bautajsFastify } = require('@axa/bautajs-fastify'); +const { BautaJS } = require('@axa/bautajs-core'); + +const apiDefinitionsV1 = require('./api-definitions-v1.json'); + +const apiDefinitionsV2 = require('./api-definitions-v2.json'); + +const bautaJsV1 = new BautaJS({ + apiDefinition: apiDefinitionsV1, + resolversPath: './server/v1/resolvers*.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +const bautaJsV2 = new BautaJS({ + apiDefinition: apiDefinitionsV2, + resolversPath: './server/v2/resolvers*.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +(async () => { + fastify + .register(bautajsFastify, { + bautajsInstance: bautaJsV1, + prefix: '/v1/', + apiBasePath: '/api/' + }) + .after(() => { + bautaJsV2.inheritOperationsFrom(bautaJsV1); + fastify.register(bautajsFastify, { + bautajsInstance: bautaJsV2, + prefix: '/v2/', + apiBasePath: '/api/' + }); + }); + + fastify.listen( + { + host: '0.0.0.0', + port: 8181 + }, + err => { + if (err) throw err; + fastify.log.info('Server listening on localhost:', fastify.server.address().port); + } + ); +})(); diff --git a/packages/bautajs-fastify-versioning-example/versioning-only-parent.js b/packages/bautajs-fastify-versioning-example/versioning-only-parent.js new file mode 100644 index 0000000..a5a857c --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/versioning-only-parent.js @@ -0,0 +1,49 @@ +const fastify = require('fastify')({ logger: true }); + +const { bautajsFastify } = require('@axa/bautajs-fastify'); +const { BautaJS } = require('@axa/bautajs-core'); + +const apiDefinitionsV1 = require('./api-definitions-v1.json'); + +const apiDefinitionsV2 = require('./api-definitions-v2.json'); + +const bautaJsV1 = new BautaJS({ + apiDefinition: apiDefinitionsV1, + resolversPath: './server/v1/resolvers.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +(async () => { + fastify + .register(bautajsFastify, { + bautajsInstance: bautaJsV1, + prefix: '/v1/', + apiBasePath: '/api/' + }) + .after(() => { + fastify.register(bautajsFastify, { + resolversPath: './server/v2/resolvers.js', + apiDefinition: apiDefinitionsV2, + prefix: '/v2/', + apiBasePath: '/api/', + inheritOperationsFrom: bautaJsV1 + }); + }); + + fastify.listen( + { + host: '0.0.0.0', + port: 8383 + }, + err => { + if (err) throw err; + fastify.log.info('Server listening on localhost:', fastify.server.address().port); + } + ); +})(); diff --git a/packages/bautajs-fastify-versioning-example/versioning-plugin-inherits.js b/packages/bautajs-fastify-versioning-example/versioning-plugin-inherits.js new file mode 100644 index 0000000..1aa29da --- /dev/null +++ b/packages/bautajs-fastify-versioning-example/versioning-plugin-inherits.js @@ -0,0 +1,60 @@ +const fastify = require('fastify')({ logger: true }); + +const { bautajsFastify } = require('@axa/bautajs-fastify'); +const { BautaJS } = require('@axa/bautajs-core'); + +const apiDefinitionsV1 = require('./api-definitions-v1.json'); + +const apiDefinitionsV2 = require('./api-definitions-v2.json'); + +const bautaJsV1 = new BautaJS({ + apiDefinition: apiDefinitionsV1, + resolversPath: './server/v1/resolvers*.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +const bautaJsV2 = new BautaJS({ + apiDefinition: apiDefinitionsV2, + resolversPath: './server/v2/resolvers*.js', + staticConfig: { + someVar: 2 + }, + strictResponseSerialization: false, + validatorOptions: { + coerceTypes: 'array' + } +}); + +(async () => { + fastify + .register(bautajsFastify, { + bautajsInstance: bautaJsV1, + prefix: '/v1/', + apiBasePath: '/api/' + }) + .after(() => { + fastify.register(bautajsFastify, { + prefix: '/v2/', + apiBasePath: '/api/', + inheritOperationsFrom: bautaJsV1, + bautajsInstance: bautaJsV2 + }); + }); + + fastify.listen( + { + host: '0.0.0.0', + port: 8282 + }, + err => { + if (err) throw err; + fastify.log.info('Server listening on localhost:', fastify.server.address().port); + } + ); +})();