-
Notifications
You must be signed in to change notification settings - Fork 20
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
Detect and serialize objects with null
prototype; provide shouldJSONSerializeBody
hook to override behavior
#90
Conversation
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. |
Looks good to me. Only comment I might possibly make is that https://github.com/sindresorhus/is-plain-obj could be a smidge cleaner and more performant. |
What about taking the opposite approach: serialize anything truthy that is not a string or Buffer? |
(That's a good fit for our FetcherRequestInit |
@glasser that change will fail one of the existing tests (that I fixed in this PR): There's some additional context, particularly in these 2: So...if you still think we should go that route I think we'd have to add some error handling around the stringify call and possibly add a hook for handling those errors? |
Hmm. Should we consider just explicitly supporting form-data in Fetcher (even though the Apollo Server/Gateway use cases don't need it)? Would require us to have a reasonably portable way of describing a FormData in TypeScript and a reasonable level of confidence that all the important implementations support it with portability between FormData implementations. (My vague memory is of looking into this at some point and deciding that they do mostly support it.) It just seems odd to introduce a bunch of complexity just in order to ensure we can pass a FormData to an API that is defined as only taking string or Buffer. |
7763c99
to
941f1b6
Compare
Simplify the conditional to the inverse: Serialize if... * it's an array or plain object * if it has a toJSON() property on it (and isn't a Buffer) Test explicitly that FormData is passed through rather than all non-plain-objects. Passing in a random class is unexpected unless it's meant to be serialized with a toJSON function.
The logic to decide on JSON serialization is currently baked in to RESTDataSource. In case customization is desired, we've provided this overridable method as an escape hatch for other use cases.
null
prototypenull
prototype; provide shouldJSONSerializeBody
hook to override behavior
// We accept arbitrary objects and arrays as body and serialize them as JSON. | ||
( | ||
Array.isArray(body) || | ||
isPlainObject(body) || |
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 still kinda feel like "anything but string or Buffer" or "anything but string, Buffer, or FormData" would be a better default — the goal of this is to produce something that the Fetch API understands, and so it feels like we should serialize anything other than what Fetch understands.
On the other hand, real Fetch APIs also take other stuff like readable streams, URLSearchParameters, TypedArray, Blob, etc, and perhaps your choice here is better for those things (and we're already moving away from "serialize anything that our Fetcher interface doesn't expect" due to FormData).
So I guess this does seem fine, given that it's just a default people can change.
This PR refines the body serialization conditional to be more straightforward (rather than a confusing mix of do's and don'ts). Bodies are JSON serialized if:
.toJSON()
function on it (with the exception ofBuffer
which we do not want to stringify)Lodash utilities are widely used and well-tested, so I went with the
isPlainObject
implementation they provide in order to correctly detect objects. The existing conditional falls short for objects with anull
prototype.For users desiring to override this behavior, we've provided the new protected method
shouldJSONSerializeBody
. This method should return aboolean
in order to tell RESTDataSource whether or not to callJSON.stringify
on the body in question.Some implementations of
fetch
support different data types (such asFormData
). You're welcome to use those, but it's your responsibility to use libraries that are compatible with each other, i.e.node-fetch
is compatible withform-data
.Fixes #67
Fixes #68
Ref: apollographql/apollo-server#5070