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

Preserve body on request object passed to willSendRequest; fix string and Buffer body handling #89

Merged
merged 19 commits into from
Nov 29, 2022

Conversation

trevor-scheer
Copy link
Member

@trevor-scheer trevor-scheer commented Nov 10, 2022

The v4 update introduced multiple regressions w.r.t. the modifiedRequest object that I added.

  1. body was no longer being added to the intermediary request object before calling willSendRequest
  2. modifiedRequest.body was never being set in the case that the incoming body was a string or Buffer

This change resolves both by reverting to what we previously had in v3 (preserving the properties on the incoming request object). The types had to be updated accordingly. Due to how path is now handled in v4, the willSendRequest signature is now (path, request).

I'm a bit disappointed in the complexity of the typings in here. We make multiple incremental refinements to the request object:

  1. first by ensuring headers/params, effectively adding one level of WithRequired to our incoming request type
  2. second by refining the body type to drop the object from the union since those are stringified

Our hooks expose the request object that we're building at various points in the construction of the request so these types are part of the public API - kind of confusing and difficult to name in ways that are simple and sensible.
i.e. RequestWithHeadersAndParams and RequestWithHeadersAndParamsAndBodyIsCompatibleWithFetch

Fixes #83

@codesandbox-ci
Copy link

codesandbox-ci bot commented Nov 10, 2022

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.

@trevor-scheer
Copy link
Member Author

@marcin-zajac would you mind testing out the fix here and letting me know if it resolves the issue for you? Builds are in the codesandbox ci link (my most recent build at the time of writing this can be installed via npm i https://pkg.csb.dev/apollographql/datasource-rest/commit/36c5b4ec/@apollo/datasource-rest)

@trevor-scheer trevor-scheer force-pushed the trevor/update-modifiedrequest-body branch from 36c5b4e to dcbcc1d Compare November 10, 2022 20:16
@trevor-scheer
Copy link
Member Author

One drawback to this implementation: hooks get the stringified version of things, meaning they'll have to re-JSON.parse() the content if they're interested in it. We could optionally provide an additional argument (like originalBody) or something if that seems valuable.

@leonbe02
Copy link

@trevor-scheer Can you also include in this PR the ability to send POST requests with Content-Type: application/x-www-form-urlencoded with the body being a string ? Currently the code is ignoring the body if it is a url encoded form which is a very common use case for older APIs that don't use JSON.

@trevor-scheer
Copy link
Member Author

@leonbe02 that sounds like a reasonable suggestion, but do you think it belongs with this PR for a particular reason? I think it's a separate concern which I'd be happy to address in a different PR unless you have an argument for these pieces of work being the same concern.

Opening a separate issue would be helpful for me if you don't mind. Please be as descriptive as possible. Are there any current workarounds you're employing?

@leonbe02
Copy link

leonbe02 commented Nov 15, 2022

@trevor-scheer I bring it up in this PR because this PR claims to resolve #83 which mentions the application/x-www-form-urlencoded bug and you're touching the same lines of code that would need to be updated to resolve the bug. Simply removing the body: undefined part of modifiedRequest would allow for the body to be a string and pass thru to the fetch function.

@trevor-scheer trevor-scheer force-pushed the trevor/update-modifiedrequest-body branch from 1aecfc7 to 8758734 Compare November 16, 2022 00:43
@trevor-scheer
Copy link
Member Author

@leonbe02 let me know if the changes I've made match your expectation. For typing reasons, it's not as simple as passing the body through straight from the request object, but I can append it without serializing when it's a string which seems reasonable. Of the possible types (undefined, object, Buffer, string), these should all be accounted for now.

I added 2 commits: one with a test to show what was failing, and a second which implements the fix and brings the test to passing.

Copy link

@leonbe02 leonbe02 left a comment

Choose a reason for hiding this comment

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

Looks good, thanks for doing that!

@trevor-scheer
Copy link
Member Author

Thanks for calling it out and taking the time to review 👍

@glasser
Copy link
Member

glasser commented Nov 18, 2022

didn't full review yet, but make sure to update the commit message with the second change that was added, and to write a changeset.

src/RESTDataSource.ts Outdated Show resolved Hide resolved
src/RESTDataSource.ts Outdated Show resolved Hide resolved
The v3 implementation of RESTDataSource did not have the concept of a "modified"
request. The params and headers were updated in place and the body was passed
directly through to the willSendRequest and resolveURL hooks. The body was then
updated if necessary, meaning neither of those hooks actually saw the final
outgoing request.

The updated implementation for v4 was indeed a regression, where the original
body was no longer included on the request object before those hooks were called.

To remediate this, let's fully build our modified request object (including final
updates to the body and headers) before we call any hooks. This resolves the
undefined body regression, and does a better job of reporting the actual outgoing
request to the willSendRequest and resolveURL hooks`.

This does not restore original v3 behavior, but it is not a breaking change
against v4 since it is strictly additive. There is a slight change in behavior in
that when the body is JSON stringified (from an array or object), the response
headers' content-type will be updated to reflect that if not already set. I would
consider this also additive.

Fixes #83
This commit undoes destructive changes to the semantics of `willSendRequest`
i.e. when it is called and with what parameters.

The original `body` is now passed through to the `augmentedRequest` as
soon as it is created and before calling `willSendRequest`, so the
body can now always be observed when the hook is called.

Additionally, `Buffer`s are now passed through (and tested against)
@trevor-scheer trevor-scheer force-pushed the trevor/update-modifiedrequest-body branch from a2e1461 to 7bbbdfa Compare November 29, 2022 01:07
@@ -1,5 +1,5 @@
export {
RESTDataSource,
RequestOptions,
WillSendRequestOptions,
AugmentedRequest,
Copy link
Member Author

Choose a reason for hiding this comment

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

The name change here alone makes this a v5 change. Could continue exporting this as an alias, but maybe the naming is still up in the air anyway.

@trevor-scheer trevor-scheer changed the title Update modifiedRequest.body before it's used by hooks Preserve body on request object passed to willSendRequest; fix string and Buffer body Nov 29, 2022
'@apollo/datasource-rest': patch
---

The v4 update introduced multiple regressions w.r.t. the intermediary `modifiedRequest` object that was added.
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 changeset should be more clear that this is about willSendRequest?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure I agree, up above we agreed that the string | Buffer problem was a glaring regression. In any case, I've updated the changeset to call out both separately and a bit more clearly.

.changeset/cuddly-cars-sparkle.md Outdated Show resolved Hide resolved
src/RESTDataSource.ts Outdated Show resolved Hide resolved
src/RESTDataSource.ts Show resolved Hide resolved
src/RESTDataSource.ts Outdated Show resolved Hide resolved
src/RESTDataSource.ts Show resolved Hide resolved
@trevor-scheer
Copy link
Member Author

@glasser I can't find out how to reply to your comment about the type name.

Worth mentioning this type is also part of the resolveURL signature, so it's used for both hooks. Maybe IntermediaryRequest makes sense? We now have the concept (in code) of an incoming vs. outgoing request.

Copy link
Member

@glasser glasser left a comment

Choose a reason for hiding this comment

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

Think this looks good modulo these concerns — lmk if you want me to take another look after any adjustments.

.changeset/cuddly-cars-sparkle.md Outdated Show resolved Hide resolved
// While tempting, this union can't be reduced / factored out to just
// Omit<WithRequired<GetRequest | RequestWithBody, 'headers'>, 'params'> & { params: URLSearchParams }
// TS loses its ability to discriminate against the method (and its consequential `body` type)
export type AugmentedRequest = (
Copy link
Member

Choose a reason for hiding this comment

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

Might be worth a comment that the point here is basically, this is like DataSourceRequest but with headers and params normalized for convenience in your callbacks.

BTW unrelated but it seems like method shouldn't be optional in GetRequest/RequestWithBody?

README.md Outdated Show resolved Hide resolved
src/RESTDataSource.ts Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
.changeset/tidy-spoons-nail.md Outdated Show resolved Hide resolved
@trevor-scheer trevor-scheer changed the title Preserve body on request object passed to willSendRequest; fix string and Buffer body Preserve body on request object passed to willSendRequest; fix string and Buffer body handling Nov 29, 2022
@trevor-scheer trevor-scheer merged commit 4a249ec into main Nov 29, 2022
@trevor-scheer trevor-scheer deleted the trevor/update-modifiedrequest-body branch November 29, 2022 23:15
@github-actions github-actions bot mentioned this pull request Nov 29, 2022
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.

POST request body is undefined when use willSendRequest
3 participants