UNPKG

@superhero/http-server-using-oas

Version:

Integrates the HTTP server and OAS (OpenAPI Specification) @superhero components

294 lines (251 loc) 11.7 kB
import Core from '@superhero/core' import Request from '@superhero/http-request' import assert from 'node:assert' import util from 'node:util' import { suite, test, beforeEach } from 'node:test' util.inspect.defaultOptions.depth = 3 suite('@superhero/http-server-using-oas', () => { let core beforeEach(async () => { if(beforeEach.skip) { return } if(core) { await core.destroy() } core = new Core() await core.add('@superhero/oas') await core.add('@superhero/http-server') await core.add('@superhero/http-server-using-oas') core.locate.set('placeholder', { dispatch: () => 'placeholder' }) }) test('Can set a simple specification', async () => { const specification = { paths: { '/foo': { get: { responses: { 200: {} }}, post: { responses: { 200: {} }} }, '/bar': { put: { responses: { 200: {} }} }}} core.locate.config.assign({ oas:specification }) await core.bootstrap() const oas = core.locate('@superhero/http-server-using-oas') oas.setOasRoute('/foo', 'get', 'placeholder') oas.setOasRoute('/foo', 'post', 'placeholder') oas.setOasRoute('/bar', 'put', 'placeholder') assert.ok(oas.server.router.has('get /foo'), 'Route for "get /foo" should be added') assert.ok(oas.server.router.has('post /foo'), 'Route for "post /foo" should be added') assert.ok(oas.server.router.has('put /bar'), 'Route for "put /bar" should be added') }) test('Can add middleware for requestBody content', async () => { const specification = { paths: { '/foo': { post: { requestBody : { content: { 'application/json': {} } }, responses : { 200: {} } }}}} core.locate.config.assign({ oas:specification }) await core.bootstrap() const oas = core.locate('@superhero/http-server-using-oas') oas.setOasRoute('/foo', 'post', 'placeholder') const route = oas.server.router.get('post /foo'), requestBodyMiddleware = core.locate('@superhero/http-server-using-oas/dispatcher/upstream/request-bodies'), hasRequestBodies = route.route.middlewares.includes(requestBodyMiddleware) assert.ok(hasRequestBodies, 'Middleware for requestBody should be added') assert.equal( route.route['content-type.application/json'], '@superhero/http-server/dispatcher/upstream/header/content-type/application/json') }) test('Can add middleware for parameters', async () => { const specification = { paths: { '/foo': { get: { parameters : [], responses : { 200: {} } }}}} core.locate.config.assign({ oas:specification }) await core.bootstrap() const oas = core.locate('@superhero/http-server-using-oas') oas.setOasRoute('/foo', 'get', 'placeholder') const route = oas.server.router.get('get /foo'), parametersMiddleware = core.locate('@superhero/http-server-using-oas/dispatcher/upstream/parameters'), hasParameters = route.route.middlewares.includes(parametersMiddleware) assert.ok(hasParameters, 'Middleware for parameters should be added') }) test('Specification with reference to components', async sub => { const specification = { components: { headers: { ContentType: { required: true, schema: { type: 'string' } } }, parameters: { DefaultFoo: { name: 'foo', in: 'query', required: true, schema: { '$ref': '#/components/schemas/String' }, nullable: true, default: null }, RequiredFoo: { name: 'foo', in: 'query', required: true, schema: { '$ref': '#/components/schemas/String' }}, PathFoo: { name: 'foo', in: 'path', required: true, schema: { '$ref': '#/components/schemas/String' }}, QueryFoo: { name: 'foo', in: 'query', required: false, schema: { '$ref': '#/components/schemas/String' }}, HeaderFoo: { name: 'foo', in: 'header', required: false, schema: { '$ref': '#/components/schemas/String' }} }, requestBodies: { ExampleRequestBody: { '$ref': '#/components/requestBodies/GenericRequestBody' }, GenericRequestBody: { required: true, content: { 'application/json': { schema: { '$ref': '#/components/schemas/Foo' }}} } }, responses: { SuccessResult: { description: 'Successful result', headers: { 'Content-Type': { '$ref': '#/components/headers/ContentType' }}, content: { 'application/json': { schema: { '$ref': '#/components/schemas/Result' }}} }, BadRequest: { description: 'Bad Request', content: { 'application/json': { schema: { '$ref': '#/components/schemas/Result' }}} } }, schemas: { String: { type: 'string' }, Foo: { type: 'object', properties: { foo: { '$ref': '#/components/schemas/String' }} }, Result: { type: 'object', properties: { result: { '$ref': '#/components/schemas/String' } } } } }, paths: { '/example/default': { get: { parameters: [{ '$ref': '#/components/parameters/DefaultFoo' }], responses: { 200: { '$ref': '#/components/responses/SuccessResult' }, 400: { '$ref': '#/components/responses/BadRequest' } } } }, '/example/required': { get: { parameters: [{ '$ref': '#/components/parameters/RequiredFoo' }], responses: { 200: { '$ref': '#/components/responses/SuccessResult' }, 400: { '$ref': '#/components/responses/BadRequest' } } } }, '/example/foo/{foo}': { get: { parameters: [{ '$ref': '#/components/parameters/PathFoo' }], responses: { 200: { '$ref': '#/components/responses/SuccessResult' }, 400: { '$ref': '#/components/responses/BadRequest' } } } }, '/example': { get: { parameters: [ { '$ref': '#/components/parameters/QueryFoo' }, { '$ref': '#/components/parameters/HeaderFoo' } ], responses: { 200: { '$ref': '#/components/responses/SuccessResult' }, 400: { '$ref': '#/components/responses/BadRequest' } } }, post: { requestBody: { '$ref': '#/components/requestBodies/ExampleRequestBody' }, responses: { 200: { '$ref': '#/components/responses/SuccessResult' }, 400: { '$ref': '#/components/responses/BadRequest' }}}} } } core.locate.config.assign({ oas:specification }) await core.bootstrap() const oas = core.locate('@superhero/http-server-using-oas') const dispatcher1 = { dispatch: (request, session) => session.view.body.result = request.param.foo }, dispatcher2 = { dispatch: (request, session) => session.view.body.result = request.body.foo } core.locate.set('test/dispatcher/1', dispatcher1) core.locate.set('test/dispatcher/2', dispatcher2) oas.setOasRoute('/example', 'get', 'test/dispatcher/1') oas.setOasRoute('/example', 'post', 'test/dispatcher/2') oas.setOasRoute('/example/foo/{foo}', 'get', 'test/dispatcher/1') oas.setOasRoute('/example/required', 'get', 'placeholder') oas.setOasRoute('/example/default', 'get', 'placeholder') const route = oas.server.router.get('get /example'), parametersMiddleware = core.locate('@superhero/http-server-using-oas/dispatcher/upstream/parameters'), requestBodiesMiddleware = core.locate('@superhero/http-server-using-oas/dispatcher/upstream/request-bodies'), responsesMiddleware = core.locate('@superhero/http-server-using-oas/dispatcher/downstream/responses') assert.ok(route, 'route for "get /example" should exist') assert.ok(route.route.middlewares.includes(parametersMiddleware)) assert.ok(route.route.middlewares.includes(requestBodiesMiddleware)) assert.ok(route.route.middlewares.includes(responsesMiddleware)) assert.equal(route.route['condition.method'], 'get', 'Correct GET method condition') const httpServer = core.locate('@superhero/http-server') await httpServer.listen() beforeEach.skip = true await sub.test('GET method using default parameter query parameter', async () => { const baseUrl = `http://localhost:${httpServer.gateway.address().port}`, request = new Request({ url: baseUrl, doNotThrowOnErrorStatus: true }), response = await request.get({ url: '/example/default?foo=query', headers: { 'connection': 'close', 'content-type': 'application/json' }}) assert.equal(response.status, 200, '200 status code for GET method') assert.equal(response.body.result, null, 'Correct response body for GET method') }) await sub.test('GET method not using required parameter', async () => { const baseUrl = `http://localhost:${httpServer.gateway.address().port}`, request = new Request({ url: baseUrl, doNotThrowOnErrorStatus: true }), response = await request.get({ url: '/example/required', headers: { 'connection': 'close', 'content-type': 'application/json' }}) assert.equal(response.status, 400, '400 status code for GET method') }) await sub.test('GET method using bar parameter', async () => { const baseUrl = `http://localhost:${httpServer.gateway.address().port}`, request = new Request({ url: baseUrl, doNotThrowOnErrorStatus: true }), response = await request.get({ url: '/example/foo/bar', headers: { 'connection': 'close', 'content-type': 'application/json' }}) assert.equal(response.status, 200, '200 status code for GET method') assert.equal(response.body.result, 'bar', 'Correct response body for GET method') }) await sub.test('GET method using header parameter', async () => { const baseUrl = `http://localhost:${httpServer.gateway.address().port}`, request = new Request({ url: baseUrl, doNotThrowOnErrorStatus: true }), response = await request.get({ url: '/example', headers: { 'foo':'header', 'connection': 'close', 'content-type': 'application/json' }}) assert.equal(response.status, 200, '200 status code for GET method') assert.equal(response.body.result, 'header', 'Correct response body for GET method') }) await sub.test('POST method using request body', async () => { const baseUrl = `http://localhost:${httpServer.gateway.address().port}`, request = new Request({ url: baseUrl, doNotThrowOnErrorStatus: true }), response = await request.post({ url: '/example', body: { foo: 'body' }, headers: { 'connection': 'close', 'content-type': 'application/json' }}) assert.equal(response.status, 200, '200 status code for POST method') assert.equal(response.body.result, 'body', 'Correct response body for POST method') }) beforeEach.skip = false await httpServer.close() }) })