File Uploads
GraphQL Yoga supports GraphQL Multipart Request Specification which basically allows you to upload files via HTTP and consume the binary data inside GraphQL Resolvers.
In GraphQL Yoga, you consume uploaded files or blobs as WHATWG standard File
or Blob
objects you might be familiar from the browser's API.
Check out MDN documentation to learn more about File
objects
You can use any kind of client supports GraphQL Upload specification. Check out here to find GraphQL Client solutions
Example
You only need to add a scalar type definition for file uploads in your schema. The name of the scalar doesn't matter.
Let's use File
in this example.
file-upload-example.ts
import { createYoga } from 'graphql-yoga'
// Provide your schema
const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
scalar File
type Query {
greetings: String!
}
type Mutation {
readTextFile(file: File!): String!
}
`,
resolvers: {
Query: {
greetings: () => 'Hello World!'
},
Mutation: {
/**
* TypeScript type `File` is globally available.
* You don't need to install/import anything else
* for both `File` GraphQL Scalar and this type
*/
readTextFile: async (_, { file }: { file: File }) => {
const textContent = await file.text()
return textContent
}
}
}
})
})
// Start the server and explore http://localhost:4000/graphql
const server = createServer(yoga)
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
Test your GraphQL Server with cURL
curl localhost:4000/graphql \
-F operations='{ "query": "mutation ($file: File!) { readTextFile(file: $file) }", "variables": { "file": null } }' \
-F map='{ "0": ["variables.file"] }' \
-F 0=@mytext.txt
With GraphQL Nexus
You need to create a scalar type for file upload in your schema.
nexus-file-upload-example.ts
import {
makeSchema,
scalarType,
mutationField,
queryField,
arg,
nonNull
} from 'nexus'
import { createYoga } from 'graphql-yoga'
const FileScalar = scalarType({
name: 'File',
asNexusMethod: 'file',
description: 'The `File` scalar type represents a file upload.',
sourceType: 'File'
})
const greetings = queryField('greetings', {
type: 'String',
resolve: () => 'Hello World!'
})
const readTextFile = mutationField('readTextFile', {
type: 'String',
args: { file: nonNull(arg({ type: 'File' })) },
resolve: async (parent, { file }, ctx) => {
const textContent = await file.text()
return textContent
}
})
const schema = makeSchema({
types: [FileScalar, greetings, readTextFile]
})
const yoga = createYoga({
schema: schema
})
// Start the server and explore http://localhost:4000/graphql
const server = createServer(yoga)
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
Disabling Multipart/File Upload Processing
If you want to disable multipart request processing for some reason, you can pass multipart: false
to prevent Yoga from handling multipart requests.
createYoga({ multipart: false })
Configuring Multipart Request Processing (only for Node.js)
In Node.js, you can configure the limits of the multipart request processing such as maximum allowed file size, maximum numbers of files, etc.
Fetch API's Request.formData
method doesn't have any options to configure the limits of Multipart request processing.
Instead we can configure our Fetch API ponyfill to manage that.
import { createFetch } from '@whatwg-node/fetch'
import { createYoga } from 'graphql-yoga'
createYoga({
fetchAPI: createFetch({
// We prefer `node-fetch` over `undici` and current unstable Node's implementation
useNodeFetch: true,
formDataLimits: {
// Maximum allowed file size (in bytes)
fileSize: 1000000,
// Maximum allowed number of files
files: 10,
// Maximum allowed size of content (operations, variables etc...)
fieldSize: 1000000,
// Maximum allowed header size for form data
headerSize: 1000000
}
})
})