n8n Helpers — Referência e Exemplos em JavaScript

Sumário

Operações com binários

Nesta subseção cobrimos helpers que leem, escrevem, convertem e manipulam dados binários.

assertBinaryData(item, propertyName)

Valida se o item contém binário no `propertyName` e lança erro informativo caso contrário.

// Exemplo
try {
  assertBinaryData(item, 'binary.data');
} catch (err) {
  throw new Error('Arquivo binário obrigatório: ' + err.message);
}

Caso real: validar que um arquivo enviado por webhook é imagem antes de gerar thumbnail. Se faltar, o workflow registra o erro e envia notificação ao remetente.

// Caso real: validar imagem recebida via webhook
try {
  assertBinaryData(item, 'binary.payload');
  const meta = getBinaryMetadata(item, 'binary.payload');
  if (!meta.mimeType.startsWith('image/')) throw new Error('Não é imagem');
} catch (err) {
  await httpRequest({ method: 'POST', uri: 'https://hooks.example.com/notify', body: { error: err.message }, json: true });
  return; // encerra node atual
}

getBinaryDataBuffer(item, propertyName)

Retorna um Buffer contendo os bytes do binário, pronto para processamento ou upload.

// Exemplo
const buf = getBinaryDataBuffer(item, 'binary.file');
const size = buf.length; // use como quiser

Caso real: ler um PDF recebido, extrair texto com OCR externo e enviar resultado para indexação.

// Caso real: enviar PDF para serviço de OCR
const pdfBuf = getBinaryDataBuffer(item, 'binary.pdf');
const res = await httpRequestWithAuthentication('https://ocr.example.com/parse', 'ocrCred', {
  method: 'POST',
  body: pdfBuf,
  headers: { 'Content-Type': 'application/pdf' },
});
const text = await res.text();
await writeContentToFile(getStoragePath('ocr/' + item.json.id + '.txt'), text);

prepareBinaryData(data, mimeType, fileName)

Cria um objeto binário no formato esperado pelo n8n (base64 + metadata) a partir de Buffer/string.

// Exemplo
const buffer = Buffer.from('hello world');
const binary = prepareBinaryData(buffer, 'text/plain', 'hello.txt');

Caso real: preparar conteúdo gerado dinamicamente (relatório CSV) para anexar em um email enviado por outro node.

// Caso real: gerar CSV e anexar
const csv = 'col1,col2\n1,2\n3,4';
const bin = prepareBinaryData(Buffer.from(csv,'utf8'), 'text/csv', 'report.csv');
setBinaryDataBuffer(item, 'binary.report', bin.data, { mimeType: bin.meta.mimeType, fileName: bin.meta.fileName });

setBinaryDataBuffer(item, propertyName, buffer, meta)

Define um campo binário em `item` a partir de um Buffer e metadados (mimetype, filename).

// Exemplo
setBinaryDataBuffer(item, 'binary.image', buffer, { mimeType: 'image/png', fileName: 'img.png' });

Caso real: após redimensionar imagem localmente (sharp), salvar de volta no item para posterior upload ao CDN pelo node de armazenamento.

// Caso real: resize + salvar no item
const sharp = require('sharp');
const resized = await sharp(buffer).resize(800).toBuffer();
setBinaryDataBuffer(item, 'binary.image', resized, { mimeType: 'image/png', fileName: 'hero.png' });

binaryToString(buffer, encoding='utf8')

Converte Buffer binário para string com o encoding desejado (útil para CSV/JSON textuais).

// Exemplo
const csv = binaryToString(buf, 'utf8');
const rows = csv.split('\n');

Caso real: receber um CSV via webhook, converter para string, parsear linhas e enviar cada linha como item individual para processamentos separados.

// Caso real: processar CSV e criar items
const csv = binaryToString(getBinaryDataBuffer(item,'binary.csv'), 'utf8');
const lines = csv.trim().split('\n').slice(1);
const out = lines.map(l => { const [a,b] = l.split(','); return { json: { a, b } }; });
return returnJsonArray(out);

Requisições HTTP e autenticação

httpRequest(options)

Wrapper simples para fetch/axios com timeouts, retries e tratamento de status. Use para chamadas sem credenciais do n8n.

// Exemplo
const res = await httpRequest({ method: 'GET', uri: 'https://api.example.com/data' });
const json = await res.json();

Caso real: consultar uma API pública de preços para normalizar preços em produtos antes de salvar no CRM.

// Caso real: normalizar preços de catálogo
const resp = await httpRequest({ method: 'GET', uri: 'https://prices.example.com/v1/prices' });
const prices = await resp.json();
item.json.price = normalizePrices(prices, item.json.sku);

request(options)

Implementação compatível com callbacks/streams; geralmente delega para `httpRequest` mas expõe mais controle.

// Exemplo
const result = await request({ uri: 'https://example.com', json: true });

Caso real: baixar arquivos grandes via streaming para armazenar sem carregar tudo em memória.

// Caso real: stream download direto para disk
const rs = await request({ uri: 'https://cdn.example.com/video.mp4', encoding: null });
const ws = createWriteStream(getStoragePath('tmp/video.mp4'));
rs.pipe(ws);

httpRequestWithAuthentication(uri, authName, options)

Faz uma requisição injetando credenciais configuradas no n8n (OAuth2, API key, etc.).

// Exemplo
const data = await httpRequestWithAuthentication('https://api.service.com/v1', 'myApiCred', { method: 'POST', body: { a:1 } });

Caso real: postar resultados agregados para uma API interna protegida por OAuth2 usando credencial armazenada no n8n.

// Caso real: enviar relatório com OAuth2
const report = generateReport(items);
await httpRequestWithAuthentication('https://internal.example.com/reports', 'internalOAuth', {
  method: 'POST',
  body: report,
  json: true,
});

requestWithAuthenticationPaginated(uri, authName, paginator)

Executa chamadas paginadas automaticamente usando estratégia de paginação (cursor/offset).

// Exemplo
for await (const page of requestWithAuthenticationPaginated('https://api.example.com/items', 'myCred')) {
  process(page.items);
}

Caso real: sincronizar catálogo de produtos de um ERP paginado para atualizar estoque local com retry e checkpoint.

// Caso real: sincronizar com checkpoint
const checkpoint = loadCheckpoint('erp-sync');
for await (const page of requestWithAuthenticationPaginated('https://erp.example.com/products', 'erpCred', { startCursor: checkpoint.cursor })) {
  upsertProducts(page.items);
  saveCheckpoint('erp-sync', { cursor: page.nextCursor });
}

Streams e arquivos

copyBinaryFile(src, dest)

Copia um arquivo binário entre storages/paths, mantendo metadados quando possível.

// Exemplo
await copyBinaryFile('/tmp/in.mp4', '/data/cache/out.mp4');

Caso real: mover gravações de chamada temporárias para bucket S3 após processamento de transcript.

// Caso real: mover gravação após transcript
await copyBinaryFile(getBinaryPath(item,'binary.call'), getStoragePath('calls/' + item.json.callId + '.mp4'));

createReadStream(path)

Retorna um stream legível (`fs.createReadStream`-like) — preferível para arquivos grandes.

// Exemplo
const rs = createReadStream('/data/bigfile.bin');
rs.pipe(process.stdout);

Caso real: enviar backup grande diretamente para armazenamento remoto via stream, evitando memória alta.

// Caso real: stream para uploader
const rs = createReadStream(getStoragePath('backups/dump.sql'));
await uploadStreamToS3(rs, 'backups/dump.sql');

getBinaryStream(item, propertyName)

Obtém um stream a partir do conteúdo binário armazenado no item (quando suportado).

// Exemplo
const stream = getBinaryStream(item, 'binary.file');
await pipelinePromise(stream, destinationStream);

Caso real: fazer transcode por chunk para serviço externo que aceita stream e grava resultado em S3.

// Caso real: transcode streaming
const inStream = getBinaryStream(item,'binary.video');
const transcodeStream = callTranscodeService(inStream);
await uploadStreamToS3(transcodeStream, getStoragePath('videos/' + item.json.id + '.mp4'));

binaryToBuffer(binaryData)

Converte a representação binária do n8n em `Buffer` para APIs Node que esperam Buffer.

// Exemplo
const buf = binaryToBuffer(item.binary.myfile);

Caso real: receber anexo base64 no item e enviar para um microserviço que só aceita Buffer multipart.

// Caso real: enviar buffer para microserviço
const buf = binaryToBuffer(item.binary.attach);
await httpRequestWithAuthentication('https://micro.example/upload', 'svcCred', { method: 'POST', body: buf, headers: { 'Content-Type':'application/octet-stream' }});

getBinaryMetadata(item, propertyName)

Retorna metadados (mimeType, fileName, size) para o binário armazenado.

// Exemplo
const meta = getBinaryMetadata(item, 'binary.file');
console.log(meta.mimeType, meta.fileName, meta.fileSize);

Caso real: usar `fileName` e `mimeType` para criar nomes amigáveis no CDN e setar headers de cache corretos.

// Caso real: metadata -> CDN path
const m = getBinaryMetadata(item,'binary.image');
const cdnPath = `images/${item.json.userId}/${m.fileName}`;
await copyBinaryFile(getBinaryPath(item,'binary.image'), getStoragePath(cdnPath));

Caminhos e escrita

getStoragePath(key)

Resolve o path físico/virtual usado pelo sistema de storage para uma chave lógica.

// Exemplo
const path = getStoragePath('workflow-123/output.png');

Caso real: gerar paths estáveis por workflow para referência em bases e para expiração automática por prefixo.

// Caso real: path estruturado por data e workflow
const p = getStoragePath(`exports/${new Date().toISOString().slice(0,10)}/${workflow.id}/report.json`);
await writeContentToFile(p, JSON.stringify(report));

getBinaryPath(item, propertyName)

Retorna o caminho subjacente onde o binário está armazenado, se disponível.

// Exemplo
const p = getBinaryPath(item, 'binary.attachment');

Caso real: usar caminho para leitura direta por um processo externo (p.ex. FFmpeg local) que espera caminho de arquivo.

// Caso real: usar em pipeline local com ffmpeg
const videoPath = getBinaryPath(item,'binary.video');
await spawn('ffmpeg',['-i', videoPath, '-vf','scale=1280:720','-c:a','copy','/tmp/out.mp4']);

writeContentToFile(path, content)

Escreve conteúdo (texto ou Buffer) em arquivo e retorna metadados. Use atomic writes quando possível.

// Exemplo
await writeContentToFile('/tmp/out.json', JSON.stringify(obj));

Caso real: gravar relatórios temporários antes de upload, e garantir escrita atômica para evitar arquivos corrompidos durante processamento concorrente.

// Caso real: escrita atômica + upload
const tmp = getStoragePath('tmp/' + Date.now() + '.json');
await writeContentToFile(tmp, JSON.stringify(report));
await copyBinaryFile(tmp, getStoragePath('reports/' + reportId + '.json'));

Utilitários gerais

copyInputItems(items)

Clona items de entrada para evitar mutação por referência ao transformar dados.

// Exemplo
const safeItems = copyInputItems(items);
safeItems.forEach(i => { i.json.processed = true; });

Caso real: ao enrichar dados em lote, usar cópias para permitir reprocessamento a partir do original em caso de falha parcial.

// Caso real: reprocessável
const safe = copyInputItems(items);
try {
  await Promise.all(safe.map(async i => await enrich(i)));
} catch (err) {
  // re-run original items sem mutação
  return copyInputItems(items);
}

returnJsonArray(jsonArray)

Formata um array JSON como retorno legível pelo n8n (array de items com json). Ideal para retornar resultados finais.

// Exemplo
return returnJsonArray([{ id:1, name: 'A' }, { id:2, name: 'B' }]);

Caso real: retornar resultados de um node de consulta que alimenta um relatório gerado por outro workflow.

// Caso real: retornar rows para next node que envia relatório
const rows = queryDb('select id, name from users limit 100');
return returnJsonArray(rows);

normalizeItems(items)

Normaliza formatos de entrada para um padrão consistente (ex: garantir array, campos esperados).

// Exemplo
const normalized = normalizeItems(maybeItems);

Caso real: unificar eventos de webhooks de diferentes provedores em um formato padrão antes de processar em massa.

// Caso real: unificar eventos
const inEvents = normalizeItems(input);
const mapped = inEvents.map(e => ({ json: { id: e.json.user_id || e.json.id, event: e.json.type } }));
return returnJsonArray(mapped);

getSSHClient(options)

Cria cliente SSH para execuções remotas seguras; use com timeout e validações de hostkey.

// Exemplo
const ssh = await getSSHClient({ host: 'example.com', username: 'ci' });
const out = await ssh.execCommand('ls -la');

Caso real: rodar manutenção em servidores legados para coletar logs e compressá-los antes de enviar ao armazenamento central.

// Caso real: coletar logs e enviar
const client = await getSSHClient({ host: 'app1.example.com', username: 'ops' });
await client.execCommand('tar -czf /tmp/logs.tar.gz /var/log/myapp');
await copyBinaryFile('/tmp/logs.tar.gz', getStoragePath('archives/app1/' + Date.now() + '.tar.gz'));

createDeferredPromise()

Gera um objeto { promise, resolve, reject } para controlar um fluxo assíncrono externamente.

// Exemplo
const deferred = createDeferredPromise();
setTimeout(() => deferred.resolve('ok'), 5000);
const value = await deferred.promise; // espera 5s

Caso real: usar deferred para aguardar callback externo (p.ex. confirmação de pagamento) que chega via webhook e resolve a promise criada no momento da requisição inicial.

// Caso real: aguardar confirmação de pagamento por webhook
const deferred = createDeferredPromise();
registerWebhookListener(paymentId, (payload) => deferred.resolve(payload));
const paymentResult = await Promise.race([deferred.promise, timeout(1000*60*10)]);
if (!paymentResult) throw new Error('Timeout aguardando pagamento');

constructExecutionMetaData(opts)

Cria metadados ricos (workflowId, runId, credentials) que devem acompanhar chamadas internas ou logs.

// Exemplo
const meta = constructExecutionMetaData({ workflowId: 123, runId: 'abc', credentials: 'myCred' });

Caso real: passar `meta` ao iniciar subworkflow para manter rastreabilidade entre execução pai e filha e centralizar logs por runId.

// Caso real: invocar subworkflow com metadata
const meta = constructExecutionMetaData({ workflowId: workflow.id, runId: execution.id, credentials: credsName });
await startSubWorkflow('process-media', items, meta);

FAQ

Como escolher entre Buffer e Stream?
Use Buffer para arquivos pequenos (<~10-20MB) quando manipulações aleatórias são necessárias. Use Stream para arquivos grandes para não esgotar a memória e permitir pipe diretamente para storage/HTTP.
Posso usar `httpRequestWithAuthentication` em workflows públicos?
Sim, mas garanta que credenciais sejam armazenadas corretamente e que permissões sejam restritas no n8n. Evite expor endpoints que possam devolver credenciais.
Como tratar erros em requisições paginadas?
Implemente retry com backoff, registre o cursor atual e permita retomar a partir do último cursor processado. Centralize o tratamento de exceções para idempotência.
Quais são os riscos de usar `createDeferredPromise`?
Promises não resolvidas podem vazar memória se não houver timeout. Sempre associe timeout e paths de cancelamento quando usar deferreds.
Onde guardar arquivos binários no n8n?
Prefira storages externos (S3, Blob) e mantenha apenas referências no banco do n8n. Use getStoragePath para resolver localização e evite salvar grandes blobs no banco de dados do n8n.

Sumário de Siglas

API: Application Programming Interface — interface de comunicação entre sistemas.

SSH: Secure Shell — protocolo para acesso remoto seguro.

JSON-LD: JSON for Linking Data — formato de metadados para SEO/FAQ.

CDN: Content Delivery Network — rede de distribuição de conteúdo.

Referências

Livros

  • Node.js Design Patterns — M. Casciaro
  • Streaming Systems — T. Akidau