Attachments

This document describes how to upload attachments using the Glue API. The process involves three main steps:

  1. Get an upload ticket - Request a signed URL for uploading

  2. Upload the file - Upload the file content to the signed URL

  3. Create a file object - Register the uploaded file in the system

  4. Use the file - Attach the file to messages or other objects

Overview

Files in Glue are uploaded directly to cloud storage using presigned URLs. The process ensures that only authorized users can upload files and that file integrity is maintained.

API Endpoints

1. Get Upload Ticket

Mutation: uploadTicket

Request a signed URL for uploading a file. This endpoint validates file metadata and returns either an existing file (if the same content was already uploaded) or a new upload ticket.

mutation UploadTicket($input: UploadTicketInput!) {
  uploadTicket(input: $input) {
    ... on File {
      id
      name
    }
    ... on UploadTicket {
      id
      url
      headers {
        name
        value
      }
      formData {
        name
        value
      }
    }
  }
}

Input Parameters:

Field
Type
Required
Description

name

String

Yes

The filename

contentLength

String

Yes

File size in bytes

contentMD5

String

Yes

Base64-encoded MD5 hash of the file content

contentType

String

Yes

MIME type of the file

metadata

UploadMetadata

No

Additional metadata (width/height for images)

UploadMetadata:

input UploadMetadata {
  width: Int
  height: Int
}

Response Types:

The uploadTicket mutation returns a union type UploadTicketResponse that can be either:

Existing File Response

If a file with the same MD5 hash already exists in the system, the API returns a complete File object. In this case there is no need to re-upload the file and the file ID can be used immediately as an attachment ID for sending a message.

{
  "uploadTicket": {
    "__typename": "File",
    "id": "fil_1h3c43PfmSQpPb0CXwRJUYs0ker",
    "name": "document.pdf",
  }
}

New Upload Ticket Response

If the file content is new, the API returns an UploadTicket object with upload instructions:

{
  "uploadTicket": {
    "__typename": "UploadTicket",
    "id": "upl_2k4m56QgnTRqQc1DXxSKVZt1ler",
    "url": "https://storage.glue.com/upload/presigned-url",
    "headers": [
      { "name": "Content-Type", "value": "application/pdf" },
      { "name": "x-amz-acl", "value": "private" }
    ],
    "formData": null
  }
}

2. Upload File Content

Once you have an UploadTicket, upload the file content to the provided URL. If FormData is absent then you will nee to perform a PUT request to the specified URL. If FormData is present, then you will need to make a multipart/form-data POST request to the specified URL. In both cases you will need to supply the headers returned in the UploadTicket.

For PUT requests (no FormData):

// Upload using PUT
await fetch(uploadTicket.url, {
  method: "PUT",
  headers: uploadTicket.headers.reduce((acc, header) => {
    acc[header.name] = header.value;
    return acc;
  }, {}),
  body: fileBuffer,
});

For POST requests (when formData is provided):

The FormData array may contain multiple entries that should be used to supply the form data for the POST. One entry will contain a value of @file which needs to be substituted for for the actual file content. The Content-Type will be multipart/form-data in order to accommodate the file data. Read more about multipart form data here.

// Upload using POST with form data
const formData = new FormData();
uploadTicket.formData.forEach(({ name, value }) => {
  if (value === "@file") {
    formData.append(name, fileBuffer, {
      contentType: contentType,
      filename: filename,
    });
  } else {
    formData.append(name, value);
  }
});

await fetch(uploadTicket.url, {
  method: "POST",
  headers: uploadTicket.headers.reduce((acc, header) => {
    acc[header.name] = header.value;
    return acc;
  }, {}),
  body: formData,
});

3. Create File Object

After successful upload, create a file object in the system.

Mutation: createFile

mutation CreateFile($input: CreateFileInput!) {
  createFile(input: $input) {
    id
    name
  }
}

Input Parameters:

Field
Type
Required
Description

uploadTicketID

String

Yes

The ID from the upload ticket

File Metadata

For images and videos, provide the following metadata which will be used to the client to show an appropriately size preview of the file before it is loaded.

type FileMetadata {
  width: Int # Image/video width in pixels
  height: Int # Image/video height in pixels
  blurHash: String # Blur hash for image previews
}

Key Points:

  • Always check __typename - The response can be either File or UploadTicket

  • Existing files are immediate - No upload step needed, file is ready to use

  • New files require upload - Must upload content then call createFile

Using Files in Messages

Once you have a file object, you can attach it to messages:

mutation SendMessage($input: MessageInput!) {
  sendMessage(input: $input) {
    id
    text
    attachments {
      ... on File {
        id
        name
        url
        fileType
        contentType
      }
    }
  }
}

Message Input:

input MessageInput {
  text: String!
  attachments: [ID!]! # Array of file IDs
  quotedMessageID: ID
}

File Object Properties

type File implements Node {
  id: ID! # Unique file identifier
  fileType: FileType! # Type classification
  name: String! # Original filename
  contentLength: String! # File size in bytes
  contentMD5: String! # MD5 hash for integrity
  contentType: String! # MIME type
  metadata: FileMetadata # Additional metadata
  previewable: Boolean # Whether file can be previewed
  url: String! # Download URL
}

Last updated

Was this helpful?