diff --git a/app.js b/app.js index 75cfdd0bf5a..daa34aa7651 100644 --- a/app.js +++ b/app.js @@ -117,10 +117,11 @@ function create (env, ctx) { /////////////////////////////////////////////////// // api and json object variables /////////////////////////////////////////////////// + const apiRoot = require('./lib/api/root')(env, ctx); var api = require('./lib/api/')(env, ctx); var api3 = require('./lib/api3/')(env, ctx); var ddata = require('./lib/data/endpoints')(env, ctx); - var notificationsV2 = require('./lib/api/notifications-v2')(app, ctx) + var notificationsV2 = require('./lib/api/notifications-v2')(app, ctx); app.use(compression({ filter: function shouldCompress (req, res) { @@ -166,6 +167,10 @@ function create (env, ctx) { }); }); + app.use('/api', bodyParser({ + limit: 1048576 * 50 + }), apiRoot); + app.use('/api/v1', bodyParser({ limit: 1048576 * 50 }), api); @@ -233,7 +238,7 @@ function create (env, ctx) { app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); - app.use('/swagger-ui-dist', (req, res, next) => { + app.use('/swagger-ui-dist', (req, res) => { res.redirect(307, '/api-docs'); }); diff --git a/lib/api/const.json b/lib/api/const.json new file mode 100644 index 00000000000..cb1421d8520 --- /dev/null +++ b/lib/api/const.json @@ -0,0 +1,4 @@ +{ + "API1_VERSION": "1.0.0", + "API2_VERSION": "2.0.0" +} \ No newline at end of file diff --git a/lib/api/root.js b/lib/api/root.js new file mode 100644 index 00000000000..275660eeae8 --- /dev/null +++ b/lib/api/root.js @@ -0,0 +1,23 @@ +'use strict'; + +function configure () { + const express = require('express') + , api = express.Router( ) + , apiConst = require('./const') + , api3Const = require('../api3/const') + ; + + api.get('/versions', function getVersion (req, res) { + + const versions = [ + { version: apiConst.API1_VERSION, url: '/api/v1' }, + { version: apiConst.API2_VERSION, url: '/api/v2' }, + { version: api3Const.API3_VERSION, url: '/api/v3' } + ]; + + res.json(versions); + }); + + return api; +} +module.exports = configure; diff --git a/tests/api.root.test.js b/tests/api.root.test.js new file mode 100644 index 00000000000..d2c3609a117 --- /dev/null +++ b/tests/api.root.test.js @@ -0,0 +1,42 @@ +'use strict'; + +const request = require('supertest'); +require('should'); + +describe('Root REST API', function() { + const self = this + , instance = require('./fixtures/api/instance') + , semver = require('semver') + ; + + this.timeout(15000); + + before(async () => { + self.instance = await instance.create({}); + self.app = self.instance.app; + self.env = self.instance.env; + }); + + + after(function after () { + self.instance.server.close(); + }); + + + it('GET /api/versions', async () => { + let res = await request(self.app) + .get('/api/versions') + .expect(200); + + res.body.length.should.be.aboveOrEqual(3); + res.body.forEach(obj => { + const fields = Object.getOwnPropertyNames(obj); + fields.sort().should.be.eql(['url', 'version']); + + semver.valid(obj.version).should.be.ok(); + obj.url.should.startWith('/api'); + }); + }); + +}); + diff --git a/tests/fixtures/api/instance.js b/tests/fixtures/api/instance.js new file mode 100644 index 00000000000..ed5b28474c9 --- /dev/null +++ b/tests/fixtures/api/instance.js @@ -0,0 +1,98 @@ +'use strict'; + +const fs = require('fs') + , path = require('path') + , language = require('../../../lib/language')() + , apiRoot = require('../../../lib/api/root') + , http = require('http') + , https = require('https') + ; + +function configure () { + const self = { }; + + self.prepareEnv = function prepareEnv({ apiSecret, useHttps, authDefaultRoles, enable }) { + + if (useHttps) { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + } + else { + process.env.INSECURE_USE_HTTP = true; + } + process.env.API_SECRET = apiSecret; + + process.env.HOSTNAME = 'localhost'; + const env = require('../../../env')(); + + if (useHttps) { + env.ssl = { + key: fs.readFileSync(path.join(__dirname, '../api3/localhost.key')), + cert: fs.readFileSync(path.join(__dirname, '../api3/localhost.crt')) + }; + } + + env.settings.authDefaultRoles = authDefaultRoles; + env.settings.enable = enable; + + return env; + }; + + + /* + * Create new web server instance for testing purposes + */ + self.create = function createHttpServer ({ + apiSecret = 'this is my long pass phrase', + useHttps = true, + authDefaultRoles = '', + enable = ['careportal', 'api'] + }) { + + return new Promise(function (resolve, reject) { + + try { + let instance = { }, + hasBooted = false + ; + + instance.env = self.prepareEnv({ apiSecret, useHttps, authDefaultRoles, enable }); + + self.wares = require('../../../lib/middleware/')(instance.env); + instance.app = require('express')(); + instance.app.enable('api'); + + require('../../../lib/server/bootevent')(instance.env, language).boot(function booted (ctx) { + instance.ctx = ctx; + instance.ctx.ddata = require('../../../lib/data/ddata')(); + instance.ctx.apiRootApp = apiRoot(instance.env, ctx); + + instance.app.use('/api', instance.ctx.apiRootApp); + + const transport = useHttps ? https : http; + + instance.server = transport.createServer(instance.env.ssl || { }, instance.app).listen(0); + instance.env.PORT = instance.server.address().port; + + instance.baseUrl = `${useHttps ? 'https' : 'http'}://${instance.env.HOSTNAME}:${instance.env.PORT}`; + + console.log(`Started ${useHttps ? 'SSL' : 'HTTP'} instance on ${instance.baseUrl}`); + hasBooted = true; + resolve(instance); + }); + + setTimeout(function watchDog() { + if (!hasBooted) + reject('timeout'); + }, 30000); + + } catch (err) { + reject(err); + } + }); + }; + + + return self; +} + +module.exports = configure(); \ No newline at end of file