UNPKG

3.52 kBJavaScriptView Raw
1// Load modules
2
3var Hoek = require('hoek');
4var Boom = require('boom');
5var MediaType = require('media-type');
6var Pack = require('../package.json');
7
8
9// Declare internals
10var internals = {};
11
12// Validates accept and content-type headers
13internals.onPreHandler = function (request, reply) {
14
15 //newer hapijs versions no longer call this on OPTIONS requests,
16 //keeping this code in for the older hapi versions that may still be using this.
17 if (request.method === 'options') {
18 return reply.continue();
19 };
20
21 if(internals.isntJsonApiRequest(request)) {
22 return reply.continue();
23 }
24
25 /**
26 * Accept parsing is complicated and there wasn't a library I could
27 * quickly find to parse them. At the expense of missing out
28 * on part of the spec, we're gonna skip this for now till
29 * we can come back to it
30 */
31 //var acceptHeader = request.headers.accept;
32 //var acceptMedia = MediaType.fromString(acceptHeader);
33
34 //if (!acceptMedia.isValid() || acceptMedia.type !== 'application' || (acceptMedia.suffix !== 'json' && acceptMedia.subtype !== 'json') ) {
35
36 //return reply(Boom.badRequest('Invalid `Accept` header. Must be able to accept `application/json` in some form'));
37 //}
38
39 //if (Object.keys(acceptMedia.parameters).length > 0) {
40
41 //return reply(Boom.notAcceptable('Media type parameters not allowed'));
42 //}
43
44 var contentType = request.headers['content-type'];
45
46 if (contentType) {
47 var contentMedia = MediaType.fromString(contentType);
48
49 //Hapi does not allow application/* w/o json suffix so we don't need to test for it
50 if (contentMedia.type !== 'application' || contentMedia.subtype !== 'vnd.api' || Object.keys(contentMedia.parameters).length > 0) {
51
52 return reply(Boom.unsupportedMediaType('Only `application/vnd.api+json` content-type supported'));
53 }
54 }
55 return reply.continue();
56};
57
58// Converts Boom errors to json-api format, adds meta info, sets content-type
59internals.onPreResponse = function (request, reply) {
60
61 var response = request.response;
62
63 if (request.method === 'options') {
64 return reply.continue();
65 }
66
67 if(internals.isntJsonApiRequest(request)) {
68 return reply.continue();
69 }
70
71 if (response.isBoom) {
72 var error = {
73 title: response.output.payload.error,
74 status: response.output.statusCode,
75 detail: response.output.payload.message
76 };
77 response.output.payload = {
78 errors: [error],
79 meta: Hoek.applyToDefaults({id: request.id}, internals.meta)
80 };
81 response.output.headers['content-type'] = 'application/vnd.api+json';
82 } else {
83 if (response.source) {
84 response.source.meta = Hoek.applyToDefaults({id: request.id}, internals.meta);
85 }
86 response.headers['content-type'] = 'application/vnd.api+json';
87 }
88 return reply.continue();
89};
90
91internals.isntJsonApiRequest = function (request) {
92 if(!request.headers.accept) {
93 return true;
94 }
95
96 if (request.headers.accept.indexOf('application/vnd.api+json') === -1) {
97 return true;
98 }
99
100 return false;
101}
102
103// Exports
104
105exports.register = function (plugin, options, done) {
106
107 internals.meta = options.meta || {};
108
109 plugin.ext('onPreHandler', internals.onPreHandler);
110 plugin.ext('onPreResponse', internals.onPreResponse);
111
112 return done();
113};
114
115exports.register.attributes = {
116 name: Pack.name,
117 version: Pack.version
118};