"Can parse content" answer for `undefined` mediaType
Schoonology opened this issue · 4 comments
I'm happy to submit a pull request solving this problem, but I want to talk through the design first.
The server I'm currently working on is getting some bad JSON requests. I cannot change the client, so I have to work with what I've got. That said, it's not providing a Content-Type
header, so the Request's mediaType
property is undefined
. That, in turn, makes its canParseContent
property true
, and parseContent
tries to handle the content as if it's application/x-www-form-urlencoded
.
Questions:
- What should
canParseContent
be in this situation? - If we continue to try to parse content without a
Content-Type
, should wetry { JSON.parse(...) }
as a part of our guessing game? - Should
Request
have a configurable "defaultContentType" to attempt if it'sundefined
?
When the Content-Type
header is missing a mach.Request
should only assume the request is application/x-www-form-urlencoded
(and therefore parseable) if it's a POST
, which I assume you're getting. If this is the case then I'd like to leave the behavior of canParseContent
as-is since this is the default behavior of web browsers submitting forms.
If your only problem is that the request is missing the Content-Type
header, my recommended would be to force mach to use its JSON parser on the request content. You can do this by manually set the Content-Type
in your request handler, e.g.:
function (request) {
// Force mach to handle the request as JSON.
request.headers['Content-Type'] = 'application/json';
return request.parseContent().then(function (params) {
// The client gave us valid JSON.
return 200;
}, function (error) {
// The request body failed to parse as JSON. Maybe it's not valid?
return 403;
});
}
It might be a good idea to put this in a middleware.
function enforceJson(app) {
return function (request) {
var headers = request.headers;
if (!headers['Content-Type']) headers['Content-Type'] = 'application/json';
return request.call(app);
}
}
Does that help?
@Schoonology Just following up on this. Did I answer your question?
Thanks for following up on this. You definitely answered the question, and I think I wound up doing something similar. It's on a personal project I haven't been able to visit for a while (hence the radio silence), but I'll take a look tonight.
I'll confirm that your expectations match what I was experiencing, and close or comment appropriately.
For posterity, the solution above solves the problem nicely. An alternative approach is to build middleware that always parses the content as JSON within said middleware:
stack.use(function (app) {
return function (request) {
return mach.utils.bufferStream(request.content)
.then(function (body) {
try {
request.body = JSON.parse(String(body))
} catch(e) {
request.body = {}
}
return request.call(app)
})
}
})