I have an express GraphQL endpoint with a resolver that accepts a single file. The resolver includes a simple validation of the file being received.
The problem is that when the validation fails, there is no way to immediately return the error to the front end, as throwing an error will not force the uploading request to be interrupted.
An over-simplified example:
fileUpload: async (parent, { file, otherdata }) => {
const isValid = (some logic here)
if(!isValid)
throw new ApolloError('upload parameters not valid')
//No need to get this far,
//we could have rejected the request already by examining otherdata,
//or the stream could be already created for max time utilization
const { createReadStream, filename, mimetype, encoding } = await file;
const readStream = await createReadStream()
...
}
Expected behavior: The resolver returns the usual {errors:[], data:null} object - or the error itself - depending on the error-policy option.
Actual behavior: The error is thrown in the backend but the request remains pending in the frontend.
I have already unsuccessfully tried the following:
Some clarifications:
I understand that uploading files using GraphQL is borderline supported functionality, but in this case we are talking about a rather basic operation.
I would appreciate any suggestions!
It turns out that this is default express behavior and has absolutely nothing to do with the GraphQL interface. The pure express version of the solution can be found here.
The request and response objects should be passed to the resolver context:
const apollo = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => {
return {
req,
res
};
}
});
Then in the resolver, according to the example:
fileUpload: async (parent, { file, otherdata }, {req, res}) => {
const isValid = (some logic here)
if(!isValid){
res.send(403).send("Some message")
// Throwing ApolloError could also work,
// in which case response object would not be required, but not tested.
// throw new ApolloError('upload parameters not valid')
return req.destroy()
}
//No need to get this far,
//we could have rejected the request already by examining otherdata,
//or the stream could be already created for max time utilization
const { createReadStream, filename, mimetype, encoding } = await file;
const readStream = await createReadStream()
...
}