Guia completo para carregar arquivos para o Blue usando mutações GraphQL ou API REST
Visão Geral
Este guia demonstra como carregar arquivos para o Blue usando duas abordagens diferentes:
- Carregamento Direto via GraphQL (Recomendado) - Carregamento simples em uma etapa com limite de tamanho de arquivo de 256MB
- Carregamento via API REST - Processo em três etapas que suporta arquivos maiores de até 4.8GB
Esta é uma comparação dos dois métodos:
Recurso | Carregamento GraphQL | Carregamento via API REST |
---|---|---|
Complexity | Simple (one request) | Complex (three steps) |
File Size Limit | 256MB per file | 4.8GB per file |
Batch Upload | Up to 10 files | Single file only |
Implementation | Direct mutation | Multi-step process |
Best For | Most use cases | Large files only |
Carregamento de Arquivos via GraphQL
O método de carregamento via GraphQL fornece uma maneira simples e direta de carregar arquivos com uma única solicitação.
uploadFile
Carrega um único arquivo para o sistema de armazenamento de arquivos e cria uma referência de arquivo no banco de dados.
Entrada:
file: Upload!
- O arquivo a ser carregado (usando multipart/form-data)projectId: String!
- ID ou slug do projeto onde o arquivo será armazenadocompanyId: String!
- ID ou slug da empresa onde o arquivo será armazenado
Retorna: File!
- O objeto de arquivo criado
Exemplo:
mutation UploadFile($input: UploadFileInput!) {
uploadFile(input: $input) {
id
uid
name
size
type
extension
shared
createdAt
project {
id
name
}
folder {
id
title
}
}
}
uploadFiles
Carrega vários arquivos para o sistema de armazenamento de arquivos e cria referências de arquivos no banco de dados.
Entrada:
files: [Upload!]!
- Array de arquivos a serem carregados (máx. 10)projectId: String!
- ID ou slug do projeto onde os arquivos serão armazenadoscompanyId: String!
- ID ou slug da empresa onde os arquivos serão armazenados
Retorna: [File!]!
- Array de objetos de arquivo criados
Exemplo:
mutation UploadFiles($input: UploadFilesInput!) {
uploadFiles(input: $input) {
id
uid
name
size
type
extension
shared
createdAt
}
}
Implementação do Cliente
Apollo Client (JavaScript)
Carregamento de Um Único Arquivo:
import { gql } from '@apollo/client';
const UPLOAD_FILE = gql`
mutation UploadFile($input: UploadFileInput!) {
uploadFile(input: $input) {
id
uid
name
size
type
extension
shared
createdAt
}
}
`;
// Using file input
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
const { data } = await uploadFile({
variables: {
input: {
file: file,
projectId: "project_123", // or "my-project-slug"
companyId: "company_456" // or "my-company-slug"
}
}
});
@@CB##f959ab83-76e1-4e18-9eb3-ef26b9744731##CB@@javascript
const UPLOAD_FILES = gql`
mutation UploadFiles($input: UploadFilesInput!) {
uploadFiles(input: $input) {
id
uid
name
size
type
extension
shared
createdAt
}
}
`;
// Using multiple file inputs
const fileInputs = document.querySelectorAll('input[type="file"]');
const files = Array.from(fileInputs).map(input => input.files[0]).filter(Boolean);
const { data } = await uploadFiles({
variables: {
input: {
files: files,
projectId: "project_123", // or "my-project-slug"
companyId: "company_456" // or "my-company-slug"
}
}
});
Vanilla JavaScript
Single File Upload:
<!-- HTML -->
<input type="file" id="fileInput" />
<button onclick="uploadFile()">Upload File</button>
async function uploadFile() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!file) {
alert('Please select a file');
return;
}
// Create GraphQL mutation
const query = `
mutation UploadFile($input: UploadFileInput!) {
uploadFile(input: $input) {
id
name
size
type
extension
createdAt
}
}
`;
// Prepare form data
const formData = new FormData();
formData.append('operations', JSON.stringify({
query: query,
variables: {
input: {
file: null, // Will be replaced by file
projectId: "your_project_id", // or "your-project-slug"
companyId: "your_company_id" // or "your-company-slug"
}
}
}));
formData.append('map', JSON.stringify({
"0": ["variables.input.file"]
}));
formData.append('0', file);
try {
const response = await fetch('/graphql', {
method: 'POST',
body: formData,
headers: {
// Don't set Content-Type - let browser set it with boundary
'Authorization': 'Bearer your_auth_token'
}
});
const result = await response.json();
if (result.errors) {
console.error('Upload failed:', result.errors);
alert('Upload failed: ' + result.errors[0].message);
} else {
console.log('Upload successful:', result.data.uploadFile);
alert('File uploaded successfully!');
}
} catch (error) {
console.error('Network error:', error);
alert('Network error during upload');
}
}
@@CB##862c4d7b-2b18-466b-ad00-7431489b6d2a##CB@@html
<!-- HTML -->
<input type="file" id="filesInput" multiple />
<button onclick="uploadFiles()">Upload Files</button>
@@CB##0976926a-0c5c-4268-9bf5-091dbc1a97ee##CB@@javascript
async function uploadFiles() {
const filesInput = document.getElementById('filesInput');
const files = Array.from(filesInput.files);
if (files.length === 0) {
alert('Please select files');
return;
}
if (files.length > 10) {
alert('Maximum 10 files allowed');
return;
}
const query = `
mutation UploadFiles($input: UploadFilesInput!) {
uploadFiles(input: $input) {
id
name
size
type
extension
createdAt
}
}
`;
const formData = new FormData();
// Create file placeholders for variables
const fileVariables = files.map((_, index) => null);
formData.append('operations', JSON.stringify({
query: query,
variables: {
input: {
files: fileVariables,
projectId: "your_project_id", // or "your-project-slug"
companyId: "your_company_id" // or "your-company-slug"
}
}
}));
// Create map for file replacements
const map = {};
files.forEach((_, index) => {
map[index.toString()] = [`variables.input.files.${index}`];
});
formData.append('map', JSON.stringify(map));
// Append actual files
files.forEach((file, index) => {
formData.append(index.toString(), file);
});
try {
const response = await fetch('/graphql', {
method: 'POST',
body: formData,
headers: {
'Authorization': 'Bearer your_auth_token'
}
});
const result = await response.json();
if (result.errors) {
console.error('Upload failed:', result.errors);
alert('Upload failed: ' + result.errors[0].message);
} else {
console.log('Upload successful:', result.data.uploadFiles);
alert(`${result.data.uploadFiles.length} arquivos carregados com sucesso!`);
}
} catch (error) {
console.error('Network error:', error);
alert('Network error during upload');
}
}
@@CB##3dd202b7-b5c9-4948-8df4-92f5f3bf7a80##CB@@bash
# Single file upload with cURL
curl -X POST \
-H "Authorization: Bearer your_auth_token" \
-F 'operations={"query":"mutation UploadFile($input: UploadFileInput!) { uploadFile(input: $input) { id name size type extension createdAt } }","variables":{"input":{"file":null,"projectId":"your_project_id","companyId":"your_company_id"}}}' \
-F 'map={"0":["variables.input.file"]}' \
-F '0=@/path/to/your/file.jpg' \
https://your-api.com/graphql
REST API Upload
Use this method for files larger than 256MB (up to 4.8GB). This approach uses a three-step process: request upload credentials, upload to storage, then register the file in the database.
Prerequisites:
- Python 3.x installed
requests
library installed:pip install requests
- A valid X-Bloo-Token-ID and X-Bloo-Token-Secret for Blue API authentication
- The file to upload (e.g., test.jpg) in the same directory as the script
This method covers two scenarios:
- Uploading to the "File Tab"
- Uploading to the "Todo File Custom Field"
Configuration
Define these constants at the top of your script:
@@CB##1851e2df-bb57-4d5c-9ba0-ad4caa91f13d##CB@@
This is diagram that shows the flow of the upload process:
Uploading to File Tab
::code-group
@@CB##d0cd9749-1703-4a34-9755-972e8b2cdf17##CB@@
::
Steps Explained
Step 1: Request Upload Credentials
- Send a GET request to
https://api.blue.cc/uploads?filename=test.jpg@@CODE##dc4387ab-bedf-4178-b1e8-ae0f6ccad80a##CODE@@files
parameter inrequests.post
to send a multipart/form-data request to the S3 URL - Ensures all fields match the policy exactly, avoiding curl's formatting issues
Step 3: Register File Metadata
- Sends a GraphQL mutation to
https://api.blue.cc/graphql
- Dynamically calculates file size with
os.path.getsize
Sample Response:
@@CB##fa0b6d2d-0de4-415c-a80a-b51c40a04a7c##CB@@
Uploading to Custom Field
::code-group
@@CB##66775eb5-690b-46a7-a742-42401c8a8ca5##CB@@
::
Steps 1-3 are the same as the File Tab process (fetch credentials, upload to S3, and register file metadata).
For step 4, you need to associate the file with a todo custom field.
- Sends a GraphQL mutation to link the file to a todo custom field
- Uses
todoId@@CODE##e88d1c12-6e3e-4c77-8e0e-2143c7a9fb41##CODE@@customFieldId
specific to your setup
Sample Response:
{
"data": {
"createTodoCustomFieldFile": true
}
}