Skip to main content
Upload a file for a record with a prepared upload, the ordinary path. Plain upload URLs and HTTP actions remain available.

Uploading a file for a record

A prepared upload already names what the file is for. A mutation checks who may upload and returns a single-use upload URL; the client sends the bytes; the server then stores the file and runs your completion mutation in one transaction. The client never passes a storage ID back, and a file whose completion refuses is never stored.
On the client, upload with the same signed-in user:
What the server guarantees:
  • maxBytes, contentType and an optional base64 sha256 are enforced while the bytes arrive. A refused upload stores nothing.
  • The completion runs as the uploader, with { file, ...args }. If it throws, no file is stored, its error reaches the client, and the bytes are reclaimed.
  • The URL is valid for an hour and for one upload. Retrying it after a lost response returns the same file without running the completion again. An unused URL expires and its reservation is collected.
  • The file is protected when the preparing mutation or the completion read protected data, and is then served only through protected delivery.

Uploading files via upload URLs

A plain upload URL stores a file that belongs to nothing until another mutation saves its storage ID, so the application must check that ID and delete files that are never saved. Prefer a prepared upload for new code. A plain upload requires the client to make 3 requests:
  1. Generate an upload URL using a mutation that calls storage.generateUploadUrl().
  2. Send a POST request with the file contents to the upload URL and receive a storage ID.
  3. Save the storage ID into your data model via another mutation.
In the first mutation that generates the upload URL you can control who can upload files to your Bijection storage. Example: File Storage with Queries and Mutations

Calling the upload APIs from a web page

Here’s an example of uploading an image via a form submission handler to an upload URL generated by a mutation:

Generating the upload URL

An upload URL can be generated by the storage.generateUploadUrl function of the MutationCtx object:
This mutation can control who is allowed to upload files. The upload URL expires in 1 hour and so should be fetched shortly before the upload is made.

Writing the new storage ID to the database

Since the storage ID is returned to the client it is likely you will want to persist it in the database via another mutation:

Limits

The file size is not limited, but upload POST request has a 2 minute timeout.

Uploading files via an HTTP action

The file upload process can be more tightly controlled by leveraging HTTP actions, performing the whole upload flow using a single request, but requiring correct CORS headers configuration. The custom upload HTTP action can control who can upload files to your Bijection storage. But note that the HTTP action request size is currently limited to 20MB. For larger files you need to use upload URLs as described above. Example: File Storage with HTTP Actions

Calling the upload HTTP action from a web page

Here’s an example of uploading an image via a form submission handler to the sendImage HTTP action defined next. The highlighted lines make the actual request to the HTTP action:

Defining the upload HTTP action

A file sent in the HTTP request body can be stored using the storage.store function of the ActionCtx object. This function returns an Id<"_storage"> of the stored file. From the HTTP action you can call a mutation to write the storage ID to a document in your database. To confirm success back to your hosted website, you will need to set the right CORS headers:
You also need to handle the pre-flight OPTIONS request: