Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Commit

Permalink
feat: Add possibility to define custom response header
Browse files Browse the repository at this point in the history
Closes #10

This can be configured globally via the new setting in `.env`.
  • Loading branch information
mischah committed Feb 21, 2018
1 parent 443b018 commit ef26157
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 15 deletions.
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ TEST_PORT=9090
# URL Prefix for the endpoints
# eg. http://localhost:8081/api/foo
API_PREFIX=/api

# Custom response header
#CUSTOM_HEADER_NAME=Authorization
#CUSTOM_HEADER_VALUE=Bearer eyJhbGciOiJIUzUxMiJ9
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ npm start

Just starts the server via node.

## Configuring endpoints
## Configure endpoints

Each endpoint needs a configuration file in `/server/api/` to define routes, http method and the response.

Expand Down Expand Up @@ -236,7 +236,7 @@ The configuration object in Detail:
* Optional
* Every subroute of this endpoint will return a HTTP error with the given status code provided by [boom](https://github.com/hapijs/boom).

## Configuration
## Configure server

The main config is handled via a file named `.env` with the following content:

Expand All @@ -255,6 +255,10 @@ TEST_PORT=9090
# eg. http://localhost:8081/api/foo
API_PREFIX=/api

# Custom response header
#CUSTOM_HEADER_NAME=Authorization
#CUSTOM_HEADER_VALUE=Bearer eyJhbGciOiJIUzUxMiJ9

```


Expand Down
4 changes: 3 additions & 1 deletion manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Confidence = require('confidence');
const Config = require('./config');
const Fs = require('fs');
const Path = require('path');
const GetCustomResponseHeader = require('./server/api/setup/lib/getCustomResponseHeader');

const criteria = {
env: process.env.NODE_ENV
Expand All @@ -22,7 +23,8 @@ const manifest = {
security: true,
cors: {
origin: ['*'],
credentials: true
credentials: true,
additionalExposedHeaders: [GetCustomResponseHeader(process.env).name]
}
},
router: {
Expand Down
9 changes: 9 additions & 0 deletions server/api/setup/lib/getCustomResponseHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

module.exports = function (env) {

return {
name: env.CUSTOM_HEADER_NAME || 'X-Powered-By',
value: env.CUSTOM_HEADER_VALUE || 'https://hapijs.com'
};
};
20 changes: 8 additions & 12 deletions server/api/setup/supportedMethod.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const Boom = require('boom');
const Fs = require('fs');
const Path = require('path');

const GetContentDisposition = require('./lib/getContentDisposition.js');
const GetContentDisposition = require('./lib/getContentDisposition');
const CustomResponseHeader = require('./lib/getCustomResponseHeader')(process.env);

module.exports = function (server, proposedRequest, settings, params, path) {

Expand Down Expand Up @@ -39,23 +40,18 @@ module.exports = function (server, proposedRequest, settings, params, path) {

}

if (proposedRequest.statusCode && proposedRequest.response) {

if (sendFile && isFile) {
return reply(response).code(proposedRequest.statusCode).type(mimeType).header('Content-Disposition', GetContentDisposition(proposedRequest.response));
}
return reply(response).code(proposedRequest.statusCode).type(mimeType);
}

if (response.isBoom === true) {
response.output.headers[CustomResponseHeader.name] = CustomResponseHeader.value;
return reply(response);
}

if (sendFile && isFile) {
return reply(response).type(mimeType).header('Content-Disposition', GetContentDisposition(proposedRequest.response));
return reply(response).code(proposedRequest.statusCode || 200).type(mimeType)
.header('Content-Disposition', GetContentDisposition(proposedRequest.response))
.header(CustomResponseHeader.name, CustomResponseHeader.value);
}

return reply(response).type(mimeType);
return reply(response).code(proposedRequest.statusCode || 200).type(mimeType)
.header(CustomResponseHeader.name, CustomResponseHeader.value);
}
};
};
2 changes: 2 additions & 0 deletions server/api/setup/unsupportedMethods.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const Boom = require('boom');
const CustomResponseHeader = require('./lib/getCustomResponseHeader')(process.env);

module.exports = function (settings, params, path) {

Expand All @@ -18,6 +19,7 @@ module.exports = function (settings, params, path) {
response = Boom.methodNotAllowed();
}

response.output.headers[CustomResponseHeader.name] = CustomResponseHeader.value;
return reply(response);
}
};
Expand Down
6 changes: 6 additions & 0 deletions test/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ lab.experiment('Manifest', () => {
Code.expect(Manifest.meta('/')).to.match(/hapi server config used by glue to compose the server/i);
done();
});

lab.test('it gets the correct custom response header', (done) => {

Code.expect(Manifest.get('/').server.connections.routes.cors.additionalExposedHeaders).to.equal(['X-Powered-By']);
done();
});
});
165 changes: 165 additions & 0 deletions test/server/api/CustomResponseHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
'use strict';

const Lab = require('lab');
const Code = require('code');
const Config = require('../../../config');
const Hapi = require('hapi');
const SetupEndpoint = require('../../../server/api/setup/');
const GetCustomResponseHeader = require('../../../server/api/setup/lib/getCustomResponseHeader');

const apiUrlPrefix = Config.get('/apiUrlPrefix');

const Endpoint = SetupEndpoint({
name: 'customResponseHeader',
urls: [
{
params: '/regularResponse',
requests: [
{ response: '/test/server/api/fixtures/response.json' }
]
},
{
params: '/fileResponse',
requests: [{
response: '/test/server/api/fixtures/example.pdf',
sendFile: true,
mimeType: 'application/pdf'
}]
},
{
params: '/boomError',
requests: [{ statusCode: 402 }]
}
]
});

const lab = exports.lab = Lab.script();
let request;
let server;

lab.beforeEach((done) => {

const plugins = [Endpoint];
server = new Hapi.Server();
server.connection({ port: Config.get('/port/web') });
server.register(plugins, (err) => {

if (err) {
return done(err);
}

done();
});
});


lab.experiment('Custom response header', () => {

lab.beforeEach((done) => {


done();
});

lab.test('should be read from .env file', (done) => {

const env = Object.assign({}, process.env);

env.CUSTOM_HEADER_NAME = 'Authorization';
env.CUSTOM_HEADER_VALUE = 'Bearer eyJhbGciOiJIUzUxMiJ9';

Code.expect(GetCustomResponseHeader(env)).to.equal({
name: 'Authorization',
value: 'Bearer eyJhbGciOiJIUzUxMiJ9'
});

done();
});

lab.test('should have a fallback if not defined in .env file', (done) => {


Code.expect(GetCustomResponseHeader(process.env)).to.equal({
name: 'X-Powered-By',
value: 'https://hapijs.com'
});

done();
});

lab.test('regular responses should have the defined response header', (done) => {

request = {
method: 'GET',
url: apiUrlPrefix + '/customResponseHeader/regularResponse'
};

server.inject(request, (response) => {

Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');

done();
});
});

lab.test('file responses should have the defined response header', (done) => {

request = {
method: 'GET',
url: apiUrlPrefix + '/customResponseHeader/fileResponse'
};

server.inject(request, (response) => {

Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');

done();
});
});

lab.test('boom errors should have the defined response header', (done) => {

request = {
method: 'GET',
url: apiUrlPrefix + '/customResponseHeader/boomError'
};

server.inject(request, (response) => {

Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');

done();
});
});

lab.test('unallowed methods of regular responses should have the defined response header', (done) => {

request = {
method: 'POST',
url: apiUrlPrefix + '/customResponseHeader/regularResponse'
};

server.inject(request, (response) => {

Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');

done();
});
});

lab.test('unallowed methods of boom errors should have the defined response header', (done) => {

request = {
method: 'POST',
url: apiUrlPrefix + '/customResponseHeader/boomError'
};

server.inject(request, (response) => {

Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');

done();
});
});

});

0 comments on commit ef26157

Please sign in to comment.