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

Issue 4359 pretty print response #7634

Merged

Conversation

dfperry5
Copy link
Contributor

@dfperry5 dfperry5 commented Jul 8, 2023

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 the runHttpQuery 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 of prettyJSONStringify(orderExecutionResultFields(graphQLResponse.body.singleResult).

@apollo-cla
Copy link

@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/

@netlify
Copy link

netlify bot commented Jul 8, 2023

👷 Deploy request for apollo-server-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 337b432

@dfperry5 dfperry5 mentioned this pull request Jul 8, 2023
@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 8, 2023

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:

Sandbox Source
Apollo Server Typescript Configuration
Apollo Server Configuration

@dfperry5
Copy link
Contributor Author

dfperry5 commented Jul 8, 2023

Apologies for all the clean up commits - but, I do have a question:

Should I be running npm run changeset-publish? I couldn't find a reference to it in the contributing.md file.

Copy link
Member

@trevor-scheer trevor-scheer left a 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!

Comment on lines 2065 to 2088
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);
});
});
Copy link
Member

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.

@trevor-scheer
Copy link
Member

No worries on the commits, they'll all be squashed into one when we land the PR.

@dfperry5
Copy link
Contributor Author

@trevor-scheer -- Updated :) Let me know if i misunderstood anything.

Comment on lines 10 to 18
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;
},
});
Copy link
Member

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 () => {
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

on it.

@trevor-scheer
Copy link
Member

npm run prettier-fix to get the prettier check passing

@dfperry5
Copy link
Contributor Author

Updated

Copy link
Member

@trevor-scheer trevor-scheer left a 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!

typeDefs,
resolvers,
stringifyResult: (value: FormattedExecutionResult) => {
return JSON.stringify(value, null, 2);;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return JSON.stringify(value, null, 2);;
return JSON.stringify(value, null, 2);

Copy link
Contributor Author

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 () => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
it('test', async () => {
it('stringifyResult', async () => {

Copy link
Contributor Author

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!

Comment on lines 168 to 174
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');
Copy link
Member

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).

Suggested change
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!"
}
}"
`);

Copy link
Contributor Author

@dfperry5 dfperry5 Jul 10, 2023

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!

Copy link
Member

@trevor-scheer trevor-scheer left a 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.

Comment on lines 263 to 267
string: internals.stringifyResult
? internals.stringifyResult(graphQLResponse.body.singleResult)
: prettyJSONStringify(
orderExecutionResultFields(graphQLResponse.body.singleResult),
),
Copy link
Member

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,
  ),
)

Copy link
Contributor Author

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Take a peak? :)

Copy link
Member

@trevor-scheer trevor-scheer left a comment

Choose a reason for hiding this comment

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

LGTM!

@trevor-scheer trevor-scheer merged commit f8a8ea0 into apollographql:main Jul 11, 2023
15 checks passed
@github-actions github-actions bot mentioned this pull request Jul 11, 2023
@dfperry5
Copy link
Contributor Author

@trevor-scheer -- Thanks so much! I'll keep an eye out for some other easier ones, unless you have some recommendations!

trevor-scheer pushed a commit that referenced this pull request Jul 21, 2023
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>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants