UNPKG

3.87 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 // Turning coverage off since we are only testing w/ newer hapi
18 // $lab:coverage:off$
19 if (request.method === 'options') {
20 return reply.continue();
21 };
22 // $lab:coverage:on$
23
24 if(internals.isntJsonApiRequest(request)) {
25 return reply.continue();
26 }
27
28 /**
29 * Accept parsing is complicated and there wasn't a library I could
30 * quickly find to parse them. At the expense of missing out
31 * on part of the spec, we're gonna skip this for now till
32 * we can come back to it
33 */
34 //var acceptHeader = request.headers.accept;
35 //var acceptMedia = MediaType.fromString(acceptHeader);
36
37 //if (!acceptMedia.isValid() || acceptMedia.type !== 'application' || (acceptMedia.suffix !== 'json' && acceptMedia.subtype !== 'json') ) {
38
39 //return reply(Boom.badRequest('Invalid `Accept` header. Must be able to accept `application/json` in some form'));
40 //}
41
42 //if (Object.keys(acceptMedia.parameters).length > 0) {
43
44 //return reply(Boom.notAcceptable('Media type parameters not allowed'));
45 //}
46
47 var contentType = request.headers['content-type'];
48
49 if (contentType) {
50 var contentMedia = MediaType.fromString(contentType);
51
52 // Ignore charset=UTF-8 media type parameter
53 // https://github.com/json-api/json-api/issues/837
54 if (contentMedia.parameters.charset === 'UTF-8') {
55 delete contentMedia.parameters.charset
56 }
57
58 //Hapi does not allow application/* w/o json suffix so we don't need to test for it
59 if (contentMedia.type !== 'application' || contentMedia.subtype !== 'vnd.api' || Object.keys(contentMedia.parameters).length > 0) {
60
61 return reply(Boom.unsupportedMediaType('Only `application/vnd.api+json` content-type supported'));
62 }
63 }
64 return reply.continue();
65};
66
67// Converts Boom errors to json-api format, adds meta info, sets content-type
68internals.onPreResponse = function (request, reply) {
69
70 var response = request.response;
71
72 if (request.method === 'options') {
73 return reply.continue();
74 }
75
76 if(internals.isntJsonApiRequest(request)) {
77 return reply.continue();
78 }
79
80 if (response.isBoom) {
81 var error = {
82 title: response.output.payload.error,
83 status: response.output.statusCode,
84 detail: response.output.payload.message
85 };
86 response.output.payload = {
87 errors: [error],
88 meta: Hoek.applyToDefaults({id: request.id}, internals.meta)
89 };
90 response.output.headers['content-type'] = 'application/vnd.api+json';
91 } else {
92 if (response.source) {
93 response.source.meta = Hoek.applyToDefaults({id: request.id}, internals.meta);
94 }
95 response.headers['content-type'] = 'application/vnd.api+json';
96 }
97 return reply.continue();
98};
99
100internals.isntJsonApiRequest = function (request) {
101 if(!request.headers.accept) {
102 return true;
103 }
104
105 if (request.headers.accept.indexOf('application/vnd.api+json') === -1) {
106 return true;
107 }
108
109 return false;
110}
111
112// Exports
113
114exports.register = function (plugin, options, done) {
115
116 internals.meta = options.meta || {};
117
118 plugin.ext('onPreHandler', internals.onPreHandler);
119 plugin.ext('onPreResponse', internals.onPreResponse);
120
121 return done();
122};
123
124exports.register.attributes = {
125 name: Pack.name,
126 version: Pack.version
127};