UNPKG

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