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

@wmmz/fn-api-client

v1.0.3

Published

Cliente HTTP para requisições API com tratamento de erros e respostas padronizadas

Readme

FN API Client

Cliente HTTP para requisições API com tratamento de erros e respostas padronizadas.

Licença TypeScript Node npm version

Tabela de Conteúdo

Instalação

# NPM
npm install @wmmz/fn-api-client

# Yarn
yarn add @wmmz/fn-api-client

# PNPM
pnpm add @wmmz/fn-api-client

Recursos

Principais Características:

  • 🔄 Tratamento padronizado de erros
  • 📝 Tipagem forte com TypeScript
  • 🎯 Callbacks para sucesso e erro
  • 🌐 Suporte a REST e GraphQL
  • ⚡ Integração com Cube
  • ⏱️ Timeout configurável
  • 🔑 Headers customizáveis
  • 📦 Zero dependências extras

Uso Básico

Cliente HTTP

import { ApiClient } from '@wmmz/fn-api-client';

// Configuração do cliente
const client = new ApiClient({
  baseURL: 'https://api.exemplo.com',
  timeout: 5000,
  headers: {
    'Authorization': 'Bearer seu-token'
  }
});

// Interceptador para adicionar token dinâmico
client.addRequestInterceptor((config) => {
  const tokens = storage.getTokens();
  if (tokens?.accessToken) {
    config.headers = {
      ...config.headers,
      Authorization: `Bearer ${tokens.accessToken}`
    };
  }
  return config;
});

// Interceptador para refresh token automático
client.addErrorInterceptor(async (error) => {
  if (error.status === 401) {
    await refreshToken();
    return {
      data: { message: 'Token renovado' },
      status: 200,
      message: 'Autenticação renovada'
    };
  }
  return error;
});

// GET com tipagem
interface Usuario {
  id: number;
  nome: string;
  email: string;
}

client.get<Usuario>('/usuarios/1', {
  onSuccess: (response) => {
    console.log('Dados:', response.data);
    console.log('Status:', response.status);
    console.log('Mensagem:', response.message);
  },
  onError: (error) => {
    console.error('Erro:', error.message);
    console.error('Status:', error.status);
    console.error('Detalhes:', error.details);
  }
});

// POST com dados
const novoUsuario = {
  nome: 'João Silva',
  email: '[email protected]'
};

client.post<Usuario>('/usuarios', novoUsuario, {
  onSuccess: (response) => console.log('Criado:', response.data),
  onError: (error) => console.error('Erro:', error.message)
});

// GET com parâmetros
client.get<UserVote>('/votos', { userId: '123', agendaId: '456' }, {
  onSuccess: (response) => console.log('Voto:', response.data),
  onError: (error) => {
    if (error.status === 404) {
      console.log('Usuário não votou ainda');
    }
  }
});

Cliente GraphQL

import { GraphQLClient } from '@wmmz/fn-api-client';

const client = new GraphQLClient({
  baseURL: 'https://api.exemplo.com/graphql',
  headers: {
    'Authorization': 'Bearer seu-token'
  }
});

// Query com variáveis
const query = `
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
      posts {
        id
        title
      }
    }
  }
`;

client.query(query, { id: '123' }, {
  onSuccess: (response) => {
    const user = response.data.user;
    console.log('Usuário:', user.name);
    console.log('Posts:', user.posts.length);
  },
  onError: (error) => console.error('Erro:', error.message)
});

// Mutation
const mutation = `
  mutation CreateUser($input: UserInput!) {
    createUser(input: $input) {
      id
      name
      email
    }
  }
`;

const variables = {
  input: {
    name: 'João Silva',
    email: '[email protected]'
  }
};

client.mutate(mutation, variables, {
  onSuccess: (response) => console.log('Criado:', response.data.createUser),
  onError: (error) => console.error('Erro:', error.message)
});

Cliente Cube GraphQL

import { CubeGraphQLClient } from '@wmmz/fn-api-client';

const client = new CubeGraphQLClient({
  baseURL: 'http://localhost:4000',
  headers: {
    'Authorization': 'Bearer seu-token'
  }
});

// Consulta com filtros e campos
await client.query('/cubejs-api/graphql', {
  limit: 20,
  offset: 0,
  where: {
    vendas: {
      total: { greaterThan: 1000 },
      status: { in: ['APROVADA', 'CONCLUIDA'] }
    },
    cliente: {
      tipo: { equals: 'PJ' }
    }
  },
  fields: {
    vendas: {
      id: true,
      total: true,
      status: true
    },
    cliente: {
      nome: true,
      tipo: true
    }
  }
}, {
  onSuccess: (response) => console.log('Dados:', response.data),
  onError: (error) => console.error('Erro:', error.message)
});

Casos de Uso

1. Interceptadores para Autenticação

const client = new ApiClient({
  baseURL: 'https://api.exemplo.com'
});

// Interceptador de requisição para token dinâmico
client.addRequestInterceptor((config) => {
  const tokens = storage.getTokens();
  if (tokens?.accessToken) {
    config.headers = {
      ...config.headers,
      Authorization: `Bearer ${tokens.accessToken}`
    };
  }
  return config;
});

// Interceptador de erro para refresh token automático
client.addErrorInterceptor(async (error) => {
  if (error.status === 401) {
    try {
      const newTokens = await refreshToken();
      storage.setTokens(newTokens);
      return {
        data: { message: 'Token renovado automaticamente' },
        status: 200,
        message: 'Autenticação renovada com sucesso'
      };
    } catch (refreshError) {
      return {
        ...error,
        message: 'Sessão expirada. Faça login novamente.'
      };
    }
  }
  return error;
});

// Interceptador de resposta para logging
client.addResponseInterceptor((response) => {
  console.log(`✅ ${response.status}: ${response.message}`);
  return response;
});

2. Upload de Arquivos

const formData = new FormData();
formData.append('file', file);

client.post('/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  },
  onSuccess: (response) => console.log('Upload concluído:', response.data),
  onError: (error) => console.error('Erro no upload:', error.message)
});

3. Consultas Cube com Agregações

const client = new CubeGraphQLClient({
  baseURL: 'http://localhost:4000'
});

await client.query('/cubejs-api/graphql', {
  where: {
    vendas: {
      data: { between: ['2024-01-01', '2024-12-31'] }
    }
  },
  fields: {
    vendas: {
      total_vendas: true,
      media_ticket: true,
      count_pedidos: true
    }
  }
}, {
  onSuccess: (response) => console.log('Métricas:', response.data),
  onError: (error) => console.error('Erro:', error.message)
});

API Reference

ApiClient

| Método | Descrição | Parâmetros | |--------|-----------|------------| | constructor | Cria uma instância do cliente | config: ApiClientConfig | | get | Realiza requisição GET | url: string, paramsOrCallbacks?: QueryParams \| RequestCallbacks<T>, callbacks?: RequestCallbacks<T> | | post | Realiza requisição POST | url: string, data: unknown, callbacks?: RequestCallbacks<T> | | put | Realiza requisição PUT | url: string, data: unknown, callbacks?: RequestCallbacks<T> | | delete | Realiza requisição DELETE | url: string, paramsOrCallbacks?: QueryParams \| RequestCallbacks<T>, callbacks?: RequestCallbacks<T> | | addRequestInterceptor | Adiciona interceptador de requisição | interceptor: RequestInterceptor | | addResponseInterceptor | Adiciona interceptador de resposta | interceptor: ResponseInterceptor | | addErrorInterceptor | Adiciona interceptador de erro | interceptor: ErrorInterceptor | | removeRequestInterceptor | Remove interceptador de requisição | interceptor: RequestInterceptor | | removeResponseInterceptor | Remove interceptador de resposta | interceptor: ResponseInterceptor | | removeErrorInterceptor | Remove interceptador de erro | interceptor: ErrorInterceptor | | clearInterceptors | Remove todos os interceptadores | void |

GraphQLClient

| Método | Descrição | Parâmetros | |--------|-----------|------------| | constructor | Cria uma instância do cliente GraphQL | config: GraphQLConfig | | query | Executa uma query GraphQL | query: string, variables?: GraphQLVariables, callbacks?: RequestCallbacks<T> | | mutate | Executa uma mutation GraphQL | mutation: string, variables?: GraphQLVariables, callbacks?: RequestCallbacks<T> |

CubeGraphQLClient

| Método | Descrição | Parâmetros | |--------|-----------|------------| | constructor | Cria uma instância do cliente Cube | config: CubeGraphQLConfig | | query | Executa uma query Cube | url: string, options?: CubeQueryOptions, callbacks?: RequestCallbacks<T> |

Tipos

Configurações

interface ApiClientConfig {
  baseURL: string;
  timeout?: number;
  headers?: Record<string, string>;
}

interface GraphQLConfig extends ApiClientConfig {}
interface CubeGraphQLConfig extends ApiClientConfig {}

Respostas e Erros

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

interface ApiError {
  message: string;
  status: number;
  code?: string;
  details?: unknown;
}

interface RequestCallbacks<T> {
  onSuccess?: (response: ApiResponse<T>) => void;
  onError?: (error: ApiError) => void;
}

Interceptadores

interface RequestConfig {
  url?: string;
  method?: string;
  headers?: Record<string, string>;
  data?: unknown;
  params?: Record<string, unknown>;
  timeout?: number;
}

interface QueryParams {
  [key: string]: string | number | boolean | undefined;
}

type RequestInterceptor = (config: RequestConfig) => RequestConfig;
type ResponseInterceptor = <T>(response: ApiResponse<T>) => ApiResponse<T>;
type ErrorInterceptor = (error: ApiError) => ApiError | Promise<ApiResponse<unknown>>;
}

Cube Query

interface CubeQueryOptions {
  limit?: number;
  offset?: number;
  where?: CubeQueryWhere;
  fields?: CubeQueryFields;
  defaultEntity?: string;
  defaultFields?: string[];
}

Contribuindo

  1. Fork o projeto
  2. Crie sua branch (git checkout -b feature/AmazingFeature)
  3. Commit suas mudanças (git commit -m 'feat: Adicionar nova funcionalidade')
  4. Push para a branch (git push origin feature/AmazingFeature)
  5. Abra um Pull Request

Changelog (em desenvolvimento | versão 1.0.1)