Skip to main content

Upload files to cloud storage

The S3Runtime can be used to interact with object storage APIs that are S3 compatible. Object storages like S3 are commonly used to cover app needs around large blob data like uploading and serving images. Most object storage services provide S3 compatible APIs including the open-source MinIO engine which you can run locally for development.

For the following example, you'll need to setup your S3 compatible store first. The following snippet can get you started using minio on docker compose:

services:
minio:
image: bitnami/minio:2022
platform: linux/amd64
restart: always
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_REGION_NAME: local
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: password
MINIO_DEFAULT_BUCKETS: "bucket:none"

We then provide the following secrets to our typegraph through metatype.yml.

typegates:
dev:
secrets:
# ..
# replace "files-upload" by the name of your typegraph
files-upload:
S3_HOST: http://localhost:9000
S3_REGION: local
S3_ACCESS_KEY: minio
S3_SECRET_KEY: password
S3_PATH_STYLE: true

Our typegraph will then look something like:

Loading...

Peruse the reference on the S3Runtime for more information.

We can then use this typegraph from our client code like so:

const image = await Deno.readFile("website/static/images/logo.png");

// Get a presigned url
const {
data: { signUploadUrl: presigned },
} = await fetch("http://localhost:7891/files-upload", {
method: "POST",
body: JSON.stringify({
query: `
query SignUploadUrl($length: Int) {
signUploadUrl(length: $length, path: "my-super-image.png")
}
`,
variables: {
length: image.length,
},
}),
}).then((r) => r.json());

// Upload the file
const upload = await fetch(presigned, {
method: "PUT",
body: image,
headers: {
"content-type": "image/png",
"content-length": image.length,
},
});

console.log(upload.status);

Uploading file using GraphQL multipart request

Metatype supports GraphQL multipart request for uploading files. You may use one of the clients in this list that support GraphQL multipart request.

const image = await Deno.readFile("website/static/images/logo.png");

const formData = new FormData();
formData.append(
"operations",
JSON.stringify({
query: `
mutation UploadImage($file: Upload!) {
upload(file: $file) {
id
path
size
contentType
}
}
`,
variables: {
file: null,
},
}),
);
formData.append("map", JSON.stringify({ 0: ["variables.file"] }));
formData.append("0", image, "logo.png");

const upload = await fetch("http://localhost:7891/files-upload", {
method: "POST",
body: formData,
});
console.log(await upload.json());