-
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
Issue 4359 pretty print response #7634
Issue 4359 pretty print response #7634
Conversation
…sult in the http query response
@dfperry5: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/ |
👷 Deploy request for apollo-server-docs pending review.Visit the deploys page to approve it
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 337b432:
|
…5/apollo-server into Issue-4359-Pretty-Print-Response
Apologies for all the clean up commits - but, I do have a question: Should I be running |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to do any publishing, but you can add a changeset by running npx changeset
. This should be a minor change. Please include a description of the change that's useful for users. Code snippets / example usage are great to have!
it('uses stringifyResult parameter', async () => { | ||
const app = await createApp({ | ||
schema, | ||
stringifyResult: (value: FormattedExecutionResult) => { | ||
let result = JSON.stringify(value, null, 1); // stringify, with line-breaks and indents | ||
result = result.replace('it works', 'stringifyResults works!'); // replace text with something custom | ||
return result; | ||
}, | ||
}); | ||
const expected = { | ||
testString: 'stringifyResults works!', | ||
}; | ||
const query = { | ||
query: 'query test{ testString }', | ||
}; | ||
const req = request(app) | ||
.get('/') | ||
.set('apollo-require-preflight', 't') | ||
.query(query); | ||
return req.then((res) => { | ||
expect(res.status).toEqual(200); | ||
expect(res.body.data).toEqual(expected); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is specific to Apollo Server and doesn't necessarily need to be tested for all integrations. I think this might belong in ApolloServer.test.ts
instead under a describe('configuration options', ...)
block.
There seems to be a couple layers in testing this. Your replace
is clearly working as expected but the additional JSON.stringify
formatting arguments are of no consequence to this test (i.e. I can remove them and the test still passes) so I'd rather see a test that validates the actual string output (probably with toMatchInlineSnapshot
) or something similar.
Sidenote: res.body.data
is a parsed object, so it seems like res.text
would be more appropriate for validating the formatting changes.
No worries on the commits, they'll all be squashed into one when we land the PR. |
@trevor-scheer -- Updated :) Let me know if i misunderstood anything. |
.changeset/pink-jobs-accept.md
Outdated
const server = new ApolloServer({ | ||
typeDefs, | ||
resolvers, | ||
stringifyResult: (value: FormattedExecutionResult) => { | ||
let result = JSON.stringify(value, null, 10000) // modify response | ||
result = result.replace('world', 'stringifyResults works!'); // replace text with something custom | ||
return result; | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't use the suggest feature here due to character escaping but if you could surround the example with code fences for markdown readers that would be nice.
```ts
code example
```
Maybe for the example we just provide the most common transform people use for pretty print? Not sure the replacement is going to be a common use case.
return JSON.stringify(value, null, 2);
@@ -2060,6 +2061,33 @@ export function defineIntegrationTestSuiteHttpServerTests( | |||
expect(res.body.errors[0].message).toEqual(expected); | |||
}); | |||
}); | |||
|
|||
it('uses stringifyResult parameter', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can just remove this test altogether with the existence of the other test. It looks like there are a handful of snapshot files that were generated due to using toMatchSnapshot
instead of toMatchInlineSnapshot
- we can delete those too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on it.
|
Updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few last minor tweaks and this is good to go!
.changeset/pink-jobs-accept.md
Outdated
typeDefs, | ||
resolvers, | ||
stringifyResult: (value: FormattedExecutionResult) => { | ||
return JSON.stringify(value, null, 2);; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return JSON.stringify(value, null, 2);; | |
return JSON.stringify(value, null, 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yikes! :P Good catch.
@@ -141,6 +141,40 @@ describe('ApolloServer construction', () => { | |||
// @ts-expect-error | |||
takesConfig({ modules: [] }); | |||
}); | |||
describe('with configuration options', () => { | |||
it('test', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it('test', async () => { | |
it('stringifyResult', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sigh - sorry this was a dumb one. Rushing through it!
const { body } = await server.executeHTTPGraphQLRequest(request); | ||
expect(JSON.stringify(body)).toMatchInlineSnapshot( | ||
`"{\"kind\":\"complete\",\"string\":\"{\\n \\\"data\\\": {\\n \\\"hello\\\": \\\"stringifyResults works!\\\"\\n }\\n}\"}"`, | ||
); | ||
// const result = singleResult(body); | ||
// expect(result.errors).toBeUndefined(); | ||
// expect(result.data?.hello).toBe('world'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little weird to stringify the response body for snapshotting, I think this is what you're looking for and we get a better visual of the result (included some cleanup of stray code).
const { body } = await server.executeHTTPGraphQLRequest(request); | |
expect(JSON.stringify(body)).toMatchInlineSnapshot( | |
`"{\"kind\":\"complete\",\"string\":\"{\\n \\\"data\\\": {\\n \\\"hello\\\": \\\"stringifyResults works!\\\"\\n }\\n}\"}"`, | |
); | |
// const result = singleResult(body); | |
// expect(result.errors).toBeUndefined(); | |
// expect(result.data?.hello).toBe('world'); | |
const { body } = await server.executeHTTPGraphQLRequest(request); | |
assert(body.kind === 'complete'); | |
expect(body.string).toMatchInlineSnapshot(` | |
"{ | |
"data": { | |
"hello": "stringifyResults works!" | |
} | |
}" | |
`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, this is what i was hoping would happen. But, I didn't realize i needed this line:
assert(body.kind === 'complete');
Thanks for my walking me through it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last round of feedback, looking good.
packages/server/src/runHttpQuery.ts
Outdated
string: internals.stringifyResult | ||
? internals.stringifyResult(graphQLResponse.body.singleResult) | ||
: prettyJSONStringify( | ||
orderExecutionResultFields(graphQLResponse.body.singleResult), | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I didn't catch this earlier. I'd like to preserve the orderExecutionResultFields
call in both cases since that's a spec concern. So maybe we do this instead, let me know what you thing:
- make the
internals.stringifyResult
not optional (keep the configuration optional) - default the internals property to
prettyJSONStringify
if it's not configured - change the call here to just:
string: internals.stringifyResult(
orderExecutionResultFields(
graphQLResponse.body.singleResult,
),
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me -- making change now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take a peak? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@trevor-scheer -- Thanks so much! I'll keep an eye out for some other easier ones, unless you have some recommendations! |
This PR was opened by the [Changesets release](/~https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @apollo/server@4.8.0 ### Minor Changes - [#7634](#7634) [`f8a8ea08f`](f8a8ea0) Thanks [@dfperry5](/~https://github.com/dfperry5)! - Updating the ApolloServer constructor to take in a stringifyResult function that will allow a consumer to pass in a function that formats the result of an http query. Usage: ```ts const server = new ApolloServer({ typeDefs, resolvers, stringifyResult: (value: FormattedExecutionResult) => { return JSON.stringify(value, null, 2); }, }); ``` ## @apollo/server-integration-testsuite@4.8.0 ### Patch Changes - [#7649](#7649) [`d33acdfdd`](d33acdf) Thanks [@mastrzyz](/~https://github.com/mastrzyz)! - Add missing `supertest` dependency - [#7632](#7632) [`64f8177ab`](64f8177) Thanks [@renovate](/~https://github.com/apps/renovate)! - Update graphql-http dependency - Updated dependencies \[[`f8a8ea08f`](f8a8ea0)]: - @apollo/server@4.8.0 Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This is a small Pull Request that addresses Issue #4359.
It adds a new function
stringifyResults(FormattedExecutionResult) => string
to the ApolloServerOptionsBase and ApolloServerInternals. This allows consumers to pass in a function that manipulates the FormattedExecutionResult into a string of their preferred format and liking. This function is used within therunHttpQuery
function. If the stringifyResult attribute is present, we will pass the FormattedExecutionResult to the supplied function, and its returned value will be the string portion of the HTTPGraphQLResponse.body. If the stringifyResult function is not provided, we fall back to the default behavior ofprettyJSONStringify(orderExecutionResultFields(graphQLResponse.body.singleResult)
.