Attachments | Glue Developers | Glue Guide

Glue API 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 need 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 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 that will be used to show an appropriately sized 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:

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
}