Exemplo em NodeJS (Express)

Este documento contém um exemplo completo de implementação da API Flowbiz em NodeJS utilizando o framework Express.

Código Completo

const express = require('express');
const app = express();
const PORT = process.env.PORT || 8080;

// Configuração
const API_KEY = process.env.API_KEY || 'sua_api_key_aqui';

app.use(express.json());

// Helper: paginação (default 50, máx 100)
function getPagination(req) {
  let offset = parseInt(req.query.offset || '0', 10);
  let limit = parseInt(req.query.limit || '50', 10);
  if (isNaN(offset) || offset < 0) offset = 0;
  if (isNaN(limit) || limit <= 0) limit = 50;
  if (limit > 100) limit = 100;
  return { offset, limit };
}

// Helper: resposta paginada
function respondPaginated(res, items, offset, limit) {
  const total = items.length;
  const data = items.slice(offset, offset + limit);
  const count = data.length;
  const hasNext = offset + count < total;
  const body = { data, total, offset, limit, count, hasNext };
  if (hasNext) body.nextOffset = offset + count;
  res.json(body);
}

// Middleware de API Key por rota
function requireApiKey(req, res, next) {
  const apiKey = req.header('X-Impulse-Key');
  if (apiKey !== API_KEY) {
    return res.status(401).json({ error: 'unauthorized', message: 'X-Impulse-Key is missing or invalid' });
  }
  next();
}

// Dados simulados
const allCategories = [
  { id: '1', name: 'Eletrônicos' },
  { id: '2', name: 'Roupas' },
  { id: '3', name: 'Acessórios' }
];

const allBrands = [
  { id: '1', name: 'Samsung' },
  { id: '2', name: 'Apple' },
  { id: '3', name: 'Nike' }
];

const allProducts = [
  {
    productId: '1',
    url: 'https://exemplo.com/produto/1',
    brand: { id: '1', name: 'Samsung' },
    category: [{ id: '1', name: 'Eletrônicos' }],
    variants: [
      { sku: 'SKU-1A', name: 'Variante A', price: 50.0, stock: 10, available: true }
    ]
  },
  {
    productId: '2',
    url: 'https://exemplo.com/produto/2',
    brand: { id: '2', name: 'Apple' },
    category: [{ id: '1', name: 'Eletrônicos' }],
    variants: [
      { sku: 'SKU-2A', name: 'Variante A', price: 75.0, stock: 5, available: true }
    ]
  }
];

const allOrders = [
  {
    platform: 'SuaPlataforma',
    orderId: '12345',
    date: '2023-06-01T10:00:00Z',
    subtotal: 100.0,
    freight: 10.0,
    discounts: 5.0,
    total: 105.0,
    currency: 'BRL',
    rawPaymentStatus: 'Pago',
    isPaid: true,
    customerId: '1',
    customerEmail: '[email protected]',
    items: [
      {
        productId: '1',
        categories: [{ id: '1', name: 'Eletrônicos' }],
        sku: 'SKU-1A',
        name: 'Produto 1',
        brand: 'Samsung',
        price: 50.0,
        quantity: 2,
        url: 'https://exemplo.com/produto/1',
        imageUrl: 'https://exemplo.com/img/1.jpg'
      }
    ],
    paymentMethods: [ { type: 'credit_card', amount: 105.0 } ],
    deliveryMethods: [ { type: 'standard', amount: 10.0 } ],
    deliveryAddress: {
      city: 'São Paulo',
      addressLine2: 'Apto 101',
      neighborhood: 'Centro',
      addressNumber: '123',
      state: 'SP',
      addressLine1: 'Rua Principal',
      postalCode: '01000-000',
      country: 'BR'
    }
  }
];

// Rotas
app.get('/api/v2/healthz', (req, res) => {
  res.json({ status: 'ok' });
});

app.get('/api/v2/categories', requireApiKey, (req, res) => {
  const { offset, limit } = getPagination(req);
  respondPaginated(res, allCategories, offset, limit);
});

app.get('/api/v2/brands', requireApiKey, (req, res) => {
  const { offset, limit } = getPagination(req);
  respondPaginated(res, allBrands, offset, limit);
});

app.get('/api/v2/products', requireApiKey, (req, res) => {
  const { offset, limit } = getPagination(req);
  respondPaginated(res, allProducts, offset, limit);
});

app.get('/api/v2/orders', requireApiKey, (req, res) => {
  const { offset, limit } = getPagination(req);
  const start = req.query.start_date;
  const end = req.query.end_date;

  const iso = /^\d{4}-\d{2}-\d{2}$/;
  if (!start || !end || !iso.test(start) || !iso.test(end)) {
    return res.status(400).json({ error: 'bad_request', message: 'start_date and end_date are required in YYYY-MM-DD format' });
  }
  const startTs = new Date(start + 'T00:00:00Z').getTime();
  const endTs = new Date(end + 'T23:59:59Z').getTime();
  if (isNaN(startTs) || isNaN(endTs)) {
    return res.status(400).json({ error: 'bad_request', message: 'Invalid date range' });
  }

  const filtered = allOrders.filter(o => {
    const ts = new Date(o.date).getTime();
    return !isNaN(ts) && ts >= startTs && ts <= endTs;
  });
  respondPaginated(res, filtered, offset, limit);
});

app.listen(PORT, () => {
  console.log(`API ouvindo na porta ${PORT}`);
});

Explicação

Este exemplo implementa uma API REST em NodeJS com Express que atende aos requisitos do padrão Flowbiz. A implementação inclui:

  1. Middleware de autenticação para validar a API Key
  2. Endpoints para listar categorias, marcas, produtos e pedidos
  3. Suporte à paginação em todos os endpoints
  4. Filtro de data no endpoint de pedidos

Para usar este exemplo, você precisará:

  1. Substituir sua_api_key_aqui pela sua chave de API real
  2. Implementar a lógica para buscar dados do seu banco de dados ou sistema de armazenamento
  3. Adaptar as estruturas de dados conforme necessário para seu caso de uso específico

Instalação das Dependências

Antes de executar o exemplo, você precisa instalar as dependências necessárias:

npm init -y
npm install express

Executando o Exemplo

Para executar este exemplo:

node app.js

O servidor será iniciado na porta 8080 e estará pronto para receber requisições.

Testando a API

Você pode testar a API usando ferramentas como Postman, cURL ou qualquer cliente HTTP. Lembre-se de incluir o header X-Impulse-Key com o valor correto em todas as requisições.

Exemplo de requisição:

curl -X GET "http://localhost:8080/api/v2/categories" \
     -H "X-Impulse-Key: sua_api_key_aqui"