Comments (12)
I just took a shot at wiring this up, so I'll share what I came up with and maybe @leebyron can comment on how to approach this in a more idiomatic way (I'm very new to GraphQL)
First I created a GraphQLFile type to represent the files in my mutations. This type just has the shape of the file object produced by multer:
GraphQLFile = new GraphQLInputObjectType({
name: 'File',
description: 'A file uploaded via multipart/form-data',
fields: () => ({
fieldname: {
type: new GraphQLNonNull(GraphQLString),
description: 'The fieldname used to POST this file.',
},
originalname: {
type: new GraphQLNonNull(GraphQLString),
description: 'The original file name.',
},
buffer: {
type: new GraphQLNonNull(GraphQLBuffer),
description: 'The file buffered in memory',
},
...
Then I setup a multer middleware that accepts any file fieldname referenced in my schema as a GraphQLFile input. So my configuration of multer looks something like this (where validFileFieldnames is derived by inspecting my schema):
multer({
storage: multer.memoryStorage()
}).fields(validFileFieldnames.map(name => ({name, maxCount: 1})));
The next missing piece was moving the file objects from where multer puts them to where express-graphql expects them to be. To do that, I wrapped the multer middleware in my own middleware that parses req.body.variables and moves the files onto req.body.variables.input, which looks something like this:
(req, res, next) => {
multerMiddleware(req, res, () => {
if (!req.files || req.files.length === 0) {
next();
return;
}
// Parse variables so we can add to them. (express-graphql won't parse them again once populated)
req.body.variables = JSON.parse(req.body.variables);
req.files.forEach(file => {
req.body.variables.input[file.fieldname] = file;
});
next();
});
};
On the clientside I generate forms with validation wired up based on my schema, so for the GraphQLFile
inputs I just render a file upload field. In my Relay mutations the files are included in the getFiles
method as shown here: https://facebook.github.io/relay/docs/api-reference-relay-mutation.html#getfiles-example and after being sent to the server and buffered by multer I am able to access the files in mutateAndGetPayload
just like any other field:
const GraphQLAddWidgetMutation = mutationWithClientMutationId({
name: 'AddWidget',
inputFields: {
name: {type: new GraphQLNonNull(GraphQLString)},
widgetPhoto: {type: new GraphQLNonNull(GraphQLFile)},
},
mutateAndGetPayload: ({name, widgetPhoto}) => {
console.log(widgetPhoto); // { originalname: 'MyPhoto.jpeg', buffer: <Buffer ...
from express-graphql.
If anyone has problems with this topic: I made an example repo basically for authentication with Relay and GraphQL but it also contains an image upload based on murz's answer.
from express-graphql.
There is an example of this in express-graphql's tests:
https://github.com/graphql/express-graphql/blob/master/src/__tests__/http-test.js#L461
Generally I suggest including a reference to the request body in the "rootValue" provided to graphql such that any field resolutions which need to access the uploaded files.
I think @murz's approach is also quite clever.
from express-graphql.
+1
from express-graphql.
+1
from express-graphql.
I expanded on the example in the test along with more comments and link to it from the README
from express-graphql.
How would you express this mutation using the mutationWithClientMutationId from graphql-relay-js?
Also, can this be modified to present the file as a stream instead of fully draining it to disk or memory first?
from express-graphql.
Hm. I added multer but I'm still getting the error "Must provide query string." from graphql-express when I try to do a multipart request...
from express-graphql.
Oh, my bad. I have to make sure that middleware comes first.
from express-graphql.
@nickretallack Would you mind explaining how you got the mutation to work using mutationWithClientMutationId?
from express-graphql.
can someone please guide me about the types, controllers and mutation for uploading a picture though GraphQL
from express-graphql.
@hassaaneforte There's several examples above. You may also find it helpful to just use graphql-upload. It works with express-graphql and provides an Upload scalar for you. See the docs for more details.
If you have additional questions, please post them on Stack Overflow or utilize any of the other available community resources, like the official Slack channel.
from express-graphql.
Related Issues (20)
- depth-limit HOT 1
- Is there a way to customize a logger HOT 1
- Unhandled errors does not provide mutation or query name HOT 1
- Graphiql playground not displayed in the browser HOT 1
- UnhandledPromiseRejectionWarning: Unhandled promise rejection HOT 1
- Why isn't the callback of app.listen() called when using express-graphql middleware? HOT 4
- Build when installed from GitHub HOT 1
- throw new MiddlewareError(`Type ${type} exists in middleware but is missing in Schema.`);
- TypeScript - merge declarations for request and response types
- Cannot install with graphql 16.0.1 HOT 10
- Update GraphQL Schema at runtime HOT 4
- Graphql 16.2.0 support HOT 9
- Processing timeout HOT 1
- About compatible version for an old graphql and node
- Swallow GraphQL errors by Express HOT 6
- Peer dependency error on new installation of graphql HOT 8
- Unmet Peer version, need to update supported dependencies HOT 9
- revert revert "Allow custom handling of runtime query errors" HOT 1
- Unable to find Prisma Client in GraphQL context. Please provide it under the `context[\"prisma\"]` key. HOT 1
- Support for running method on every call
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from express-graphql.