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

Do not serialize body values that aren't objects (like FormData) #1316

Conversation

heralden
Copy link
Contributor

@heralden heralden commented Jul 9, 2018

Would love some feedback on this. Not sure if my solution is optimal as I'm not that familiar with this.

When using RESTDataSource while setting up apollo-server and learning GraphQL, I had trouble getting my POST requests to work. Looking through the sources, I saw that the fetch method in RESTDataSource was running JSON.stringify on my FormData, causing our backend server to reject them.

I don't think this should be by design? I saw that there was coded in an exception for ArrayBuffer, but to add FormData would perhaps require pulling in the form-data dependency, which isn't very practical. So I thought we might as well only serialize body values that are javascript objects. (constructor === Object) Does this make sense?

@apollo-cla
Copy link

@uosl: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Meteor Contributor Agreement here: https://contribute.meteor.com/

@martijnwalraven
Copy link
Contributor

I don't think this will work, because a FormData instance is itself a JavaScript object. So if we want to treat form data specially, we'll probably need a dependency on form-data.

I'd like to avoid a dependency on form-data if at all possible however, because that limits us to executing on Node. And we want Apollo Server to also run on non-Node edge environments like Cloudflare Workers and fly.io. That's the reason we don't use node-fetch directly but export it from apollo-server-env. Ideally we'd do something similar for form data. It seems form-data doesn't respect the standard FormData API though.

What is it you're trying to do here exactly? What kind of request body does your server need?

If you only require x-www-form-urlencoded, you might be able to pass in URLSearchParams instead of FormData (we'd also need to add support for that, it wouldn't work right now).

@heralden
Copy link
Contributor Author

It should work. I tested this in the Node REPL. (I also commited a test for it)

> const FormData = require('form-data')
undefined
> let form = new FormData()
undefined
> form.constructor === FormData
true
> form.constructor !== Object
true

The constructor property returns a reference to the function (or ES6 class) that was used to create the instance. Maybe you're thinking of the typeof operator, which would always return "object" in these cases?

Our server expects a form-data as the request body, ie. one created like const form = new FormData(); form.append('foo', 'bar');. I could try your suggestion of using URLSearchParams, but please first let me know whether the constructor property is still not appropriate.

@martijnwalraven martijnwalraven merged commit 1022ae1 into apollographql:version-2 Jul 11, 2018
@martijnwalraven
Copy link
Contributor

Ah, you're absolutely right, I completely missed that. I was indeed thinking of typeof.

I still want to serialize objects that have a toJSON method to JSON, but I'll add an extra check for that.

@heralden heralden deleted the qf/rest-only-serialize-objects branch July 12, 2018 06:39
BridgeAR added a commit to BridgeAR/apollo-server that referenced this pull request Mar 27, 2021
The code to detect objects was malformed due to not detecting objects
with direct constructors other than `Object`.
It was implemented to prevent multipart data to be serialized. This
should be prevented by detecting the multipart header and not
the object type. This adds another safe guard to skip objects that
might not be serializable in the first place.

Refs: apollographql#1316
Refs: apollographql#2707
Fixes: https://github.com/apollographql/apollo-server/issues/1539
@BridgeAR
Copy link

This approach has caused multiple issues due to ignoring objects with a null prototype. This is done in here and many people complained about the result.

The solution would be to check for the header. No multipart header should be stringified and that way it's possible to distinguish these easily.

I opened #5070 to fix that. @uosl the solution there is to detect the content-type and to set that up front. That should accommodate your use case, right?

BridgeAR added a commit to BridgeAR/apollo-server that referenced this pull request Mar 27, 2021
The code to detect objects was malformed due to not detecting objects
with direct constructors other than `Object`.
It was implemented to prevent multipart data to be serialized. This
should be prevented by detecting the multipart header and not
the object type. This adds another safe guard to skip objects that
might not be serializable in the first place.

Refs: apollographql#1316
Refs: apollographql#2707
Fixes: https://github.com/apollographql/apollo-server/issues/1539
@heralden
Copy link
Contributor Author

@BridgeAR I apologise for the anguish my change may have caused.

My use case doesn't exist anymore as I no longer maintain the code using it, and it's likely been changed since. Please feel free to work out a better approach! Checking the content-type header definitely sounds like a better solution.

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.

4 participants