A file upload seems like a mutation. It\'s often accompanied by other data. But it\'s a big binary blob, so I\'m not sure how GraphQL can deal with it. How would you inte
I am merely sharing the findings of Marc-Andre Giroux from his blog, which is Rails-specific, so I will try to make it more generic, and providing the details of the answer provided by @Nick.
There are 2 parts:
Client-side Javascript Code
The client-side code further consists of 2 parts:
The mutation to upload file, which extends Relay.Mutation (UploadFileMutation)
// The actual mutation
class UploadFileMutation extends Relay.Mutation {
getFiles() {
return {
file: this.props.file,
};
}
// ... Rest of your mutation
}
The component that contains the React component (FileUploader) to render the UI for selecting the file, and calls the mutation to do the upload
// A react component to upload a file
class FileUploader extends React.Component {
onSubmit() {
const name = this.refs.name.value;
const file = this.refs.fileInput.files.item(0);
Relay.Store.update(
new UploadFileMutation({
name: name,
file: file,
})
);
}
// ... Rest of React component, e.g., render()
}
Server-side Server-Specific Code
The server-side code also consists of 2 parts:
For NodeJS Express server (extracted from express-graqphl test cases as pointed out by @Nick):
import multer from 'multer';
var app = express();
var graphqlHTTP = require('express-graphql');
// Multer provides multipart form data parsing.
var storage = multer.memoryStorage();
app.use(urlString(), multer({ storage }).single('file'));
// Providing the request, which contains the file MIME
// multipart as `rootValue` to enable it to
// be accessible from within Schema resolve functions.
app.use(urlString(), graphqlHTTP(req => {
return {
schema: YourMutationSchema,
rootValue: { request: req }
};
}));
Similarly, for a non-JS server, e.g., RubyOnRails:
def create
query_string = params[:query]
query_variables = ensure_hash(params[:variables]) || {}
query = GraphQL::Query.new(
YourSchema,
query_string,
variables: query_variables,
# Shove the file MIME multipart into context to make it
# accessible by GraphQL Schema Mutation resolve methods
context: { file: request.params[:file] }
)
For Javascript GraphQL Schema:
var YourMutationSchema = new GraphQLSchema({
query: new GraphQLObjectType({
// ... QueryType Schema
}),
mutation: new GraphQLObjectType({
name: 'MutationRoot',
fields: {
uploadFile: {
type: UploadedFileType,
resolve(rootValue) {
// Access file MIME multipart using
const _file = rootValue.request.file;
// ... Do something with file
}
}
}
})
});
For Rails GraphQL Schema:
AddFileMutation = GraphQL::Relay::Mutation.define do
name "AddFile"
input_field :name, !types.String
# ... Add your standard mutation schema stuff here
resolve -> (args, ctx) {
# Retrieve the file MIME multipart
file = ctx[:file]
raise StandardError.new("Expected a file") unless file
# ... Do something with file
}
end