-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[apollo-server-koa] sending wrong content-type returns 500 without description #1841
Comments
So... any news about this? |
This also applies to the default server setup without using any specific webserver (though this means that it's using Express under the hood). It looks like you receive a 500 unless you have both a valid Content-Type & valid JSON body (an invalid Content-Type has the same effect as not providing the header entirely). Here are some examples against the default sandbox. I would expect all of these to be 🚫 No Content-Type; 🚫 No body:$ curl -X POST -sD - https://apollo-server.sse.codesandbox.io/graphql
HTTP/2 500
server: nginx/1.15.9
date: Tue, 27 Aug 2019 11:14:14 GMT
x-powered-by: Express
access-control-allow-origin: *
strict-transport-security: max-age=15724800; includeSubDomains
POST body missing. Did you forget use body-parser middleware? ✅ Valid Content-Type; 🚫 No body:HTTP/2 500
server: nginx/1.15.9
date: Tue, 27 Aug 2019 11:15:56 GMT
x-powered-by: Express
access-control-allow-origin: *
strict-transport-security: max-age=15724800; includeSubDomains
POST body missing. Did you forget use body-parser middleware? 🚫 No Content-Type; ✅ Valid body:$ curl -X POST -sD - https://apollo-server.sse.codesandbox.io/graphql -d '{ "query": ""}'
HTTP/2 500
server: nginx/1.15.9
date: Tue, 27 Aug 2019 11:16:38 GMT
x-powered-by: Express
access-control-allow-origin: *
strict-transport-security: max-age=15724800; includeSubDomains
POST body missing. Did you forget use body-parser middleware? ✅ Valid Content-Type; ✅ Valid body:$ curl -X POST -sD - https://apollo-server.sse.codesandbox.io/graphql -H 'Content-Type: application/json' -d '{ "query": ""}'
HTTP/2 400
server: nginx/1.15.9
date: Tue, 27 Aug 2019 11:17:34 GMT
x-powered-by: Express
access-control-allow-origin: *
strict-transport-security: max-age=15724800; includeSubDomains
Must provide query string. ✅ Valid Content-Type; 🚫 Malformed body:$ curl -X POST -sD - https://apollo-server.sse.codesandbox.io/graphql -H 'Content-Type: application/json' -d 'x'
HTTP/2 400
server: nginx/1.15.9
date: Tue, 27 Aug 2019 11:20:02 GMT
content-type: text/html; charset=utf-8
x-powered-by: Express
access-control-allow-origin: *
content-security-policy: default-src 'self'
x-content-type-options: nosniff
strict-transport-security: max-age=15724800; includeSubDomains
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected token x in JSON at position 0<br> at JSON.parse (<anonymous>)<br> at createStrictSyntaxError (/sandbox/node_modules/apollo-server-express/node_modules/body-parser/lib/types/json.js:158:10)<br> at parse (/sandbox/node_modules/apollo-server-express/node_modules/body-parser/lib/types/json.js:83:15)<br> at /sandbox/node_modules/apollo-server-express/node_modules/body-parser/lib/read.js:121:18<br> at invokeCallback (/sandbox/node_modules/apollo-server-express/node_modules/raw-body/index.js:224:16)<br> at done (/sandbox/node_modules/apollo-server-express/node_modules/raw-body/index.js:213:7)<br> at IncomingMessage.onEnd (/sandbox/node_modules/apollo-server-express/node_modules/raw-body/index.js:273:7)<br> at IncomingMessage.emit (events.js:203:15)<br> at endReadableNT (_stream_readable.js:1129:12)<br> at process._tickCallback (internal/process/next_tick.js:63:19)</pre>
<script src="https://sse.codesandbox.io/client-hook.js"></script></body>
</html> |
@nihalgonsalves Thank you for providing the research you have here. I've tagged this for the Apollo Server 3.x release since I think it highlights some problematic patterns with the Apollo Server 2.x series that we'll need a major version bump to resolve safely. And specifically, I think any resolution should be built into the transport, which I've proposed in #3184, so as to be universally resolved in all frameworks (e.g. Koa, Express, etc.) |
There are a lot of reasons that a supposedly GraphQL request might not make it to requestPipeline: missing body, bad JSON, bad content-type, etc. Previously, many of these outcomes resulted in 5xx errors despite them being client errors (which should be 4xx), and their handling was pretty inconsistent across the integrations. Part of the confusion was a particular error message which combined "you seem to have set up your server wrong by not setting up body parsing properly" with "there was a problem parsing this request". The former is reasonable to be 500 but the latter is much more likely to be what's actually happening (you have to actively disable body parsing to make that happen!). And the recommendation was ungrammatical and express-specific despite being in apollo-server-core. But the good news is that for some reason the Express body-parser unconditionally sets `req.body` to at least `{}` before checking `content-type` (see https://github.com/expressjs/body-parser/blob/480b1cfe29af19c070f4ae96e0d598c099f42a12/lib/types/json.js#L105-L117) so we can move the "500 if body not parsed" from `apollo-server-core` to `apollo-server-express` and directly detect whether `req.body` is empty. This is a backwards-incompatible change, so we can finally implement it as v3 is imminent. The PR consists of: - Core - Make an error about needing a query be clear that it needs to be a non-empty query (the error could fire before if `query` was provided yet empty). - Make "POST body missing" error 400 instead of 500, include that it could be bad content-type or empty JSON object, and don't suggest (with poor grammar) the use of body-parser (as described above). Also show this error if httpRequest.query is a string or Buffer (this can happen with Azure Functions on JSON parse failures). - Express: Check for a sign that body-parser hasn't been applied here instead of in Core and provide a more targeted body-parser-suggesting 500. - Micro: Only parse JSON for `content-type: application/json` (like all other integrations). - Azure Functions - 400 instead of 500 for missing body - Make test more realistic on parser failures; see Core change for where this matters. Fixes #1841 (thanks to @nihalgonsalves for a good set of test cases). Fixes #4165.
Fixed on |
There are a lot of reasons that a supposedly GraphQL request might not make it to requestPipeline: missing body, bad JSON, bad content-type, etc. Previously, many of these outcomes resulted in 5xx errors despite them being client errors (which should be 4xx), and their handling was pretty inconsistent across the integrations. Part of the confusion was a particular error message which combined "you seem to have set up your server wrong by not setting up body parsing properly" with "there was a problem parsing this request". The former is reasonable to be 500 but the latter is much more likely to be what's actually happening (you have to actively disable body parsing to make that happen!). And the recommendation was ungrammatical and express-specific despite being in apollo-server-core. But the good news is that for some reason the Express body-parser unconditionally sets `req.body` to at least `{}` before checking `content-type` (see https://github.com/expressjs/body-parser/blob/480b1cfe29af19c070f4ae96e0d598c099f42a12/lib/types/json.js#L105-L117) so we can move the "500 if body not parsed" from `apollo-server-core` to `apollo-server-express` and directly detect whether `req.body` is empty. This is a backwards-incompatible change, so we can finally implement it as v3 is imminent. The PR consists of: - Core - Make an error about needing a query be clear that it needs to be a non-empty query (the error could fire before if `query` was provided yet empty). - Make "POST body missing" error 400 instead of 500, include that it could be bad content-type or empty JSON object, and don't suggest (with poor grammar) the use of body-parser (as described above). Also show this error if httpRequest.query is a string or Buffer (this can happen with Azure Functions on JSON parse failures). - Express: Check for a sign that body-parser hasn't been applied here instead of in Core and provide a more targeted body-parser-suggesting 500. - Micro: Only parse JSON for `content-type: application/json` (like all other integrations). - Azure Functions - 400 instead of 500 for missing body - Make test more realistic on parser failures; see Core change for where this matters. Fixes #1841 (thanks to @nihalgonsalves for a good set of test cases). Fixes #4165.
Expected Behavior:
Requesting the graphql endpoint using
POST
and acontent-type
header that is notapplication/json
or maybeapplication/graphql
should result in a400 Bad Request
or415 Unsupported Media Type
response from the server with a meaningful response in the body.Current Behavior:
Requesting the
POST
endpoint with e.g.content-type
headertext/plain
results in a500 Internal Server Error
response with the following body:{}
. Imho this is semantically incorrect (the client did the mistake, not the sever) and not helpful (no explanation of the error at all).Details:
I looked into this a bit and I cant find where the error is coming from. The request goes into the
bodyParser
middleware, which resolves with{}
. Then the subsequent middleware is not called anymore and I don't know why...Steps to reproduce:
Install:
npm i [email protected] [email protected] [email protected]
Run:
The text was updated successfully, but these errors were encountered: