Skip to content
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

fix responding with application/json #604

Merged
merged 5 commits into from
Sep 17, 2019
Merged

Conversation

lag-of-death
Copy link
Contributor

@lag-of-death lag-of-death commented Sep 12, 2019

Fixes #599

Checklist

  • Tests have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

What is the current behavior? What is the new behavior?

Handling application/json in Accept header is inconsistent.
This PR implements a small-footprint solution. But we should really consider a solution similar to the one proposed in: #568

The issue:

We receive: Accept: application/json, text/plain
Fastify looks into the serializers and sees that there is no serializer for application/json, but founds text/plain serializer and uses this. This is wrong. This happens because our application/json serializer is a fallback serializer (when no serializer in serializers (https://github.com/stoplightio/prism/blob/master/packages/http-server/src/serializers.ts) is found)

Why the added charset=utf8?

This is to solve the inconsistency we have. This was also addressed in #568, but didn't make it to master.

An example of the inconsistency from master:

it('returns a valid response when multiple choices are given', async () => {
const response = await server.fastify.inject({
method: 'GET',
url: '/pets/10',
headers: {
accept: 'idonotexist/something,application/json',
},
});
expect(response.statusCode).toBe(200);
expect(response.headers).toHaveProperty('content-type', 'application/json; charset=utf-8');

const response = await server.fastify.inject({
method: 'GET',
url: '/pets/10',
headers: {
accept: 'application/json,application/xml',
},
});
expect(response.statusCode).toBe(200);
expect(response.headers).toHaveProperty('content-type', 'application/json');

So, in the first example we have application/json; charset=utf-8, but in the second one only application/json.
And why is this happening? Because #568 (comment)

@lag-of-death lag-of-death changed the title [wip] fix: fix responding with application/json fix responding with application/json Sep 12, 2019
CHANGELOG.md Outdated
@@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Prism is correctly handling the `csv` collection format argument property in OAS2 documents #577
- Prism is correctly returning the response when the request has `*/*` as Accept header #578
- Prism is correctly returning a single root node with the payload for XML data #578
- Prism is correctly serializing application/json responses
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changelog messages are not as effective at communicating what happened.

"Prism is" we dont need this because we know its Prism
"correctly" we know we fixed something this in in the fixed section

What was fixed? What was it doing before? What is the scenario in which application/json scenarios were broken?

People read changelogs to find out if a specific situation that they might have noticed has been fixed, but this is not giving them that information. It's just kinda vaguely saying "something about json works better than before"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct changeling here would be a line explaining that Prism is now giving higher priority to application/json Accept content type, and it's not a "fallback" format anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover this is not in the right section, it should go in the Unreleased part

@@ -41,6 +41,10 @@ export const createServer = (operations: IHttpOperation[], opts: IPrismHttpServe
});

server.addHook('onSend', (request, reply, payload, done) => {
if (reply.getHeader('content-type') === 'application/json') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reasoning for this? If the api designer has defined the header as application/jsonwhy do we want to force the utf8 charset on there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about support for application/{dataType}+json or application/json; charset=cp1250?

Source: https://tools.ietf.org/html/rfc6839

Copy link
Contributor Author

@lag-of-death lag-of-death Sep 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@philsturgeon, @StefanDywersant, charset=utf-8 was already enforced by fastify with its default application/json serializer. We sometimes returned application/json without charset=utf-8 because... the response was wrongly serialized by some other serializer (like instead of a serializer for JSON, the data was serialized with a serializer for XML). application/{whatever}+json is here https://github.com/stoplightio/prism/blob/master/packages/http-server/src/serializers.ts#L9
Also, haven't found other charset than utf-8 logic in the code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about support for application/{dataType}+json

This scenario is already supported in the serialiser. I would not bother about the charset — it is actually something that is inferred by the browser most of the times. I am quite sure there was also a proposal to remove it completely from the content type header.

examples:
application/json:
schema:
nullable: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test might just show that no body is output when schema is a null, maybe the more standard type: string would create more confidence that this test is doing what we want for the reasons we want.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @philsturgeon here and more importantly 204 responses do not have content and so Fastify will delete it no matter if you're trying to send it to the client, so let's change this to a regular 200.

Copy link
Contributor

@XVincentX XVincentX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of changes requested, but this is going in the right direction.

@StefanDywersant I am starting to agree with you and @lag-of-death that the current serialiser package is giving us more headache than solving us problems — so I think you were right and we'll probably look for a better solution soon.

In mean time, let's stick with what we have right now.

@@ -11,6 +11,13 @@ export default [
},
serializer: JSON.stringify,
},
{
regex: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need to create a new section, you can simply modify the one at line 9 and add application/json in the array

@@ -41,6 +41,10 @@ export const createServer = (operations: IHttpOperation[], opts: IPrismHttpServe
});

server.addHook('onSend', (request, reply, payload, done) => {
if (reply.getHeader('content-type') === 'application/json') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about support for application/{dataType}+json

This scenario is already supported in the serialiser. I would not bother about the charset — it is actually something that is inferred by the browser most of the times. I am quite sure there was also a proposal to remove it completely from the content type header.

examples:
application/json:
schema:
nullable: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @philsturgeon here and more importantly 204 responses do not have content and so Fastify will delete it no matter if you're trying to send it to the client, so let's change this to a regular 200.

/check-email:
get:
responses:
"204":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, do not use 204 here.

Suggested change
"204":
"200":

@@ -22,7 +22,7 @@ mock -p 4010
curl -i -X GET http://localhost:4010/todos -H "accept: application/xml, application/json"
====expect====
HTTP/1.1 200 OK
content-type: application/json
content-type: application/json; charset=utf-8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok to return just application/json

CHANGELOG.md Outdated
@@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Prism is correctly handling the `csv` collection format argument property in OAS2 documents #577
- Prism is correctly returning the response when the request has `*/*` as Accept header #578
- Prism is correctly returning a single root node with the payload for XML data #578
- Prism is correctly serializing application/json responses
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct changeling here would be a line explaining that Prism is now giving higher priority to application/json Accept content type, and it's not a "fallback" format anymore.

@XVincentX XVincentX merged commit 8ec1761 into master Sep 17, 2019
@XVincentX XVincentX deleted the fix/handle-accept-header branch September 17, 2019 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Accept header with multiple types default to "text/plain"
4 participants