npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tiendanube/logistics-http-client

v4.0.2

Published

Package responsible for executing http requests

Downloads

614

Readme

Biblioteca responsável por executar requisições HTTP com mecanismos de retry, métricas e tratamento de erros integrados para os microsserviços de logística.

Instalação

Execute o comando:

yarn add @tiendanube/logistics-http-client

❗ Atenção: é necessário estar autenticado no registry do NPM da Nuvemshop para instalar o pacote.

Utilização

A biblioteca exporta uma interface HttpClient e uma implementação para essa interface chamada LogisticsHttpClient, que recebe a injeção de uma instância de MetricHandler e um objeto de configuração de métricas. A interface HttpClient abstrai as ações disponíveis para execução de requisições HTTP.

O cliente HTTP fornece suporte integrado para:

  • Mecanismos de retry com exponential backoff
  • Emissão automática de métricas para monitoramento de requisições
  • Tratamento de erros com tipos de erro customizados
  • Substituição de parâmetros de path para URLs dinâmicas
  • Pool de conexões TCP com reuso automático para melhor performance
  • Cache de DNS no nível da aplicação para reduzir latência e aumentar resiliência

Para começar a usar o cliente HTTP, você deve criar uma instância de LogisticsHttpClient fornecendo um metric handler e configuração:

import { LogisticsHttpClient } from '@tiendanube/logistics-http-client';
import { LoggerMetricHandler } from '@tiendanube/logistics-metric-handler';

const logger = new Logger();
const metricHandler = new LoggerMetricHandler(logger);

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'my-service',
    },
});

❗ Atenção: É obrigatório informar tanto o parâmetro metricHandler quanto o objeto de configuração com metrics para a criação de uma instância de LogisticsHttpClient.

A interface HttpClient disponibiliza os seguintes métodos HTTP:

| Método | Descrição | | -------------------------------------------------------------------------------------------- | ----------------------------------------------- | | get<T>(url: string, options: RequestOptions): Promise<Response<T>> | Executa uma requisição GET | | post<T>(url: string, data: any, options: RequestOptions): Promise<Response<T>> | Executa uma requisição POST com body | | patch<T>(url: string, data: any, options: RequestOptions): Promise<Response<T>> | Executa uma requisição PATCH com body | | put<T>(url: string, data: any, options: RequestOptions): Promise<Response<T>> | Executa uma requisição PUT com body | | delete<T>(url: string, options: RequestOptions): Promise<Response<T>> | Executa uma requisição DELETE | | request<T>(method: HttpMethod, url: string, options: RequestOptions): Promise<Response<T>> | Executa uma requisição com qualquer método HTTP |

Todos os métodos retornam uma Promise<Response<T>> onde Response contém as propriedades data e status.

Exemplo de Uso Básico

O trecho abaixo exemplifica a utilização direta da interface HttpClient para executar requisições HTTP:

import { LogisticsHttpClient } from '@tiendanube/logistics-http-client';
import { LoggerMetricHandler } from '@tiendanube/logistics-metric-handler';

const logger = new Logger();
const metricHandler = new LoggerMetricHandler(logger);

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'quotation-service',
    },
});

async function fetchUserData(userId: string) {
    try {
        const response = await httpClient.get(`https://api.example.com/users/${userId}`, {
            headers: {
                'Authorization': 'Bearer token',
                'Content-Type': 'application/json',
            },
            timeout: 5000,
            validateStatus: status => status < 400,
        });

        return response.data;
    } catch (error) {
        if (error instanceof ClientError) {
            console.error('HTTP Error:', error.statusCode, error.responseData); // Mais informações na seção "Tratamento de erros"
        }
        throw error;
    }
}

Utilização com Configuração de Retry

A biblioteca fornece mecanismos poderosos de retry com exponential backoff. Você pode configurar o comportamento de retry para diferentes cenários:

async function fetchWithRetry() {
    const response = await httpClient.get('https://api.external-service.com/data', {
        headers: { Authorization: 'Bearer token' },
        timeout: 10000,
        validateStatus: status => status < 400,
        retry: {
            retryOn502: true,
            retryOnTimeout: true,
            retryOnAbort: true,
            retryOnStatusCodes: [503, 504],
            maxAttempts: 5,
            startingDelay: 300,
            maxDelayBetweenAttempts: 2000,
            timeMultiple: 2,
            delayFirstAttempt: false,
            jitter: 'full',
        },
        pathParams: {
            storeId: '12345',
            orderId: 'order-123',
        },
        isInstabilityError: (errorCode, statusCode, responseData) => {
            return statusCode === 429 || responseData?.error === 'rate_limit';
        },
    });

    return response.data;
}

Exemplo de Uso com NestJS

Caso a aplicação em que esta biblioteca foi instalada seja baseada no framework NestJS, o exemplo abaixo pode ser utilizado como referência para sua correta utilização.

Idealmente a biblioteca será injetada como dependência da classe que está executando requisições HTTP. Para isso pode-se configurar a classe e um arquivo de módulo para realizar a injeção.

// quotation.service.ts

import { HttpClient, LogisticsHttpClient } from '@tiendanube/logistics-http-client';

@Injectable()
export class QuotationService {
    constructor(
        @Inject(LogisticsHttpClient.name)
        private readonly httpClient: HttpClient,
    ) {}

    async getExternalQuotation(storeId: string, quotationData: any) {
        const response = await this.httpClient.post(
            'https://external-api.com/stores/${storeId}/quotations',
            quotationData,
            {
                headers: {
                    'Authorization': 'Bearer secret-token',
                    'Content-Type': 'application/json',
                },
                timeout: 15000,
                validateStatus: status => status < 400,
                pathParams: { storeId },
                retry: {
                    retryOn502: true,
                    retryOnTimeout: true,
                    maxAttempts: 3,
                },
            },
        );

        return response.data;
    }
}

Então, é necessário configurar o módulo do Nest para injetar uma instância do HttpClient para o serviço que a utilizará:

// quotation.module.ts
import { LogisticsHttpClient, LOGISTICS_HTTP_CLIENT_METRIC_COMPONENT_NAME } from '@tiendanube/logistics-http-client';

@Module({
    providers: [
        {
            provide: LogisticsHttpClient.name,
            useFactory: async (logger: PinoLogger, config: MetricHandlerConfig) =>
                new LogisticsHttpClient(
                    new StatsDMetricHandler(config.statsD, logger, LOGISTICS_HTTP_CLIENT_METRIC_COMPONENT_NAME),
                    {
                        metrics: {
                            enabled: false,
                            originService: 'ne-ap-com-k8s-my-service',
                        },
                    },
                ),
            inject: [PinoLogger, metricHandlerConfig.KEY],
        },
        QuotationService,
    ],
    exports: [QuotationService],
})
export class QuotationModule {}

Configurações Avançadas

Tratamento de Erros

A biblioteca fornece uma classe customizada ClientError que estende o Error padrão com propriedades específicas para HTTP:

import { ClientError, ErrorType } from '@tiendanube/logistics-http-client';

try {
    await httpClient.get('https://api.example.com/data', options);
} catch (error) {
    if (error instanceof ClientError) {
        console.log('Method:', error.method);
        console.log('URL:', error.url);
        console.log('Status Code:', error.statusCode);
        console.log('Response Data:', error.responseData);
        console.log('Error Code:', error.errorCode);
        console.log('Error Type:', error.errorType);
    }
}

Parâmetros de Path

Use parâmetros de path para construção dinâmica de URLs:

const response = await httpClient.get('https://api.example.com/stores/${storeId}/orders/${orderId}', {
    pathParams: {
        storeId: '12345',
        orderId: 'order-67890',
    },
    validateStatus: status => status < 400,
});
// URL becomes: https://api.example.com/stores/12345/orders/order-67890

Configuração de Métricas

Controle a emissão de métricas por requisição:

// Disable metrics for a specific request
await httpClient.get('https://api.example.com/health', {
    validateStatus: status => status < 400,
    metricEnabled: false,
});

Métrica Emitida

A biblioteca emite automaticamente a métrica request (componente: logistics-http-client) para todas as requisições HTTP, a menos que desabilitada explicitamente.

Campos da métrica:

| Campo | Tipo | Descrição | | ----------------- | ----------- | ---------------------------------------------------------- | | duration | number | Duração total da requisição em milissegundos | | success | boolean | Se a requisição foi bem-sucedida | | statusCode | number | Código HTTP de resposta (200, 404, 500, etc.) | | httpMethod | string | Método HTTP usado (GET, POST, PUT, PATCH, DELETE) | | numOfAttempts | number | Número de tentativas realizadas (com retry) | | baseUrl | string | URL base (origin) do servidor de destino | | path | string | Path da requisição | | originService | string | Nome do serviço que originou a requisição | | externalStoreId | string | ID da loja externa (extraído automaticamente se disponível)| | errorType | ErrorType | Tipo de erro (Instability ou Other) se houver falha |

Exemplo de uso com StatsD:

import { StatsDMetricHandler } from '@tiendanube/logistics-metric-handler';

const metricHandler = new StatsDMetricHandler(
    statsDConfig, 
    logger, 
    'logistics-http-client'
);

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'quotation-service',
    },
});

// Cada requisição emitirá:
// logistics-http-client.request com todos os campos acima
await httpClient.get('https://api.external.com/data', options);

Essa métrica permite monitoramento completo de:

  • Latência e performance de APIs externas
  • Taxa de sucesso/erro por endpoint
  • Impacto de retries nas requisições
  • Identificação de serviços instáveis

Otimizações de Performance

A biblioteca implementa otimizações automáticas de rede para maximizar performance e resiliência em ambientes de alta carga.

Cache de DNS

Por padrão, a biblioteca implementa cache de DNS no nível da aplicação usando cacheable-lookup. Isso traz diversos benefícios:

  • Reduz latência: DNS lookups são cacheados por até 5 minutos (configurável)
  • Aumenta resiliência: Mantém cache mesmo durante falhas temporárias de DNS
  • Reduz carga: Menos consultas aos servidores DNS
  • Suporta TTL: Respeita os TTLs retornados pelos servidores DNS

Configuração padrão:

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'my-service',
    },
    dnsCache: {
        enabled: true,
        maxTtlInSeconds: 300,
        errorTtlInSeconds: 0.15,
    },
});

Desabilitar cache de DNS (não recomendado):

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'my-service',
    },
    dnsCache: {
        enabled: false,
    },
});

Como funciona

O cache de DNS usa dns.resolve4/resolve6 (consulta UDP direta) para obter IPs e TTLs dos servidores DNS:

  1. Primeira requisição: Consulta DNS direta → Cache com TTL
  2. Requisições subsequentes: Retorna do cache (latência ~0ms)
  3. Fallback inteligente: Em caso de ENOTFOUND, usa dns.lookup (que verifica /etc/hosts e cache do OS)

Isso garante compatibilidade com configurações locais (como /etc/hosts) e DNS interno do Kubernetes.

Pool de Conexões TCP

A biblioteca mantém um pool de conexões TCP reutilizáveis para cada host, eliminando a necessidade de handshakes TCP repetidos:

  • Connection reuse: Até 128 conexões simultâneas por host
  • Keep-alive: Conexões permanecem abertas para reutilização
  • Pool management: Até 50 conexões idle mantidas no pool

Configuração padrão:

const httpClient = new LogisticsHttpClient(metricHandler, {
    metrics: {
        enabled: true,
        originService: 'my-service',
    },
    agent: {
        keepAlive: true,
        keepAliveMsecs: 1000,
        maxSockets: 128,
        maxFreeSockets: 50,
        timeout: 30000,
    },
});

Parâmetros do Agent:

| Parâmetro | Padrão | Descrição | | ------------------- | ------ | --------------------------------------------------------------- | | keepAlive | true | Mantém conexões abertas para reuso | | keepAliveMsecs | 1000 | Intervalo (ms) para enviar TCP keepalive probes | | maxSockets | 128 | Máximo de conexões simultâneas por host | | maxFreeSockets | 50 | Máximo de conexões idle mantidas no pool | | timeout | 30000| Tempo (ms) que uma conexão idle permanece no pool antes de fechar |

Contribuindo

Para entender como funciona o processo de geração de novas versões para essa biblioteca, consulte a página CONTRIBUTING.