OpenAPI a Fetch

Generador de Cliente TypeScript Fetch Nativo desde OpenAPI y Swagger

Genere métodos de API en TypeScript con fetch nativo sin dependencias, serialización de consultas, cabeceras y tipos de respuesta.

6 operaciones • 4 modelos
Preajustes:
Arquitectura:
Formato de Respuesta:
YAMLBase: https://petstore3.swagger.io/api/v3
Especificación OpenAPI / Swagger (YAML o JSON)YAML
/**
 * Zero-Dependency Native Fetch TypeScript Client
 * API: Swagger Petstore (v1.0.0)
 * Base URL: https://petstore3.swagger.io/api/v3
 * Standard Web Fetch API compatible with Browsers, Node.js 18+, Bun, Deno, and Next.js
 */

/**
 * Generated TypeScript Interfaces & Models
 * API: Swagger Petstore (v1.0.0)
 * Spec: OpenAPI 3.0.3
 * Generated automatically by ToolsAA Native Fetch Generator
 */

Category {
  id?: number | undefined;
  name?: string | undefined;
}

Tag {
  id?: number | undefined;
  name?: string | undefined;
}

Pet {
  id: number;
  name: string;
  category?: Category | undefined;
  photoUrls?: string[] | undefined;
  tags?: Tag[] | undefined;
  status?: 'available' | 'pending' | 'sold' | undefined;
}

ApiResponse {
  code?: number | undefined;
  type?: string | undefined;
  message?: string | undefined;
}

// ============================================================================
// Operation Parameter Interfaces
// ============================================================================

ListPetsQueryParams {
  /** Status values that need to be considered for filter */
  status?: 'available' | 'pending' | 'sold' | undefined;
  /** How many items to return at one time (max 100) */
  limit?: number | undefined;
}

GetPetByIdPathParams {
  /** The id of the pet to retrieve */
  petId: number;
}

DeletePetPathParams {
  /** Pet id to delete */
  petId: number;
}

DeletePetHeaders {
  api_key?: string | undefined;
}

UploadFilePathParams {
  /** ID of pet to update */
  petId: number;
}

UploadFileQueryParams {
  additionalMetadata?: string | undefined;
}


// ============================================================================
// Runtime ApiError & Client Infrastructure
// ============================================================================

export class ApiError extends Error {
  readonly status: number;
  readonly statusText: string;
  readonly data: unknown;
  readonly headers: Headers;

  constructor(status: number, statusText: string, data: unknown, headers: Headers) {
    super(`HTTP ${status} ${statusText}`);
    this.name = 'ApiError';
    this.status = status;
    this.statusText = statusText;
    this.data = data;
    this.headers = headers;
  }
}

FetchClientConfig {
  baseUrl?: string;
  headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
  customFetch?: typeof fetch;
  timeoutMs?: number;
  onRequest?: (url: string, init: RequestInit) => void | Promise<void>;
  onResponse?: (response: Response) => void | Promise<void>;
}

RequestOptions extends Omit<RequestInit, 'body' | 'headers'> {
  headers?: Record<string, string>;
  query?: Record<string, any>;
  timeoutMs?: number;
}

ApiResponseEnvelope<T> {
  data: T;
  status: number;
  headers: Headers;
}

function serializeQuery(query?: Record<string, any>): string {
  if (!query) return '';
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(query)) {
    if (value === undefined || value === null) continue;
    if (Array.isArray(value)) {
      value.forEach((v) => params.append(key, String(v)));
    } else {
      params.append(key, String(value));
    }
  }
  const str = params.toString();
  return str ? `?${str}` : '';
}

async function executeFetch<T>(
  config: FetchClientConfig,
  method: string,
  path: string,
  options?: RequestOptions & { body?: any }
): Promise<T> {
  const baseUrl = (config.baseUrl || 'https://petstore3.swagger.io/api/v3').replace(/\/+$/, '');
  const queryString = serializeQuery(options?.query);
  const fullUrl = `${baseUrl}${path.startsWith('/') ? path : '/' + path}${queryString}`;

  let dynamicHeaders: Record<string, string> = {};
  if (typeof config.headers === 'function') {
    dynamicHeaders = await config.headers();
  } else if (config.headers) {
    dynamicHeaders = config.headers;
  }

  const headers = new Headers({
    ...dynamicHeaders,
    ...options?.headers,
  });

  let requestBody: any = undefined;
  if (options?.body !== undefined) {
    if (typeof FormData !== 'undefined' && options.body instanceof FormData) {
      requestBody = options.body;
      // Browser sets multipart boundary automatically, remove conflicting content-type
      headers.delete('Content-Type');
    } else if (typeof Blob !== 'undefined' && options.body instanceof Blob) {
      requestBody = options.body;
    } else if (typeof options.body === 'object') {
      if (!headers.has('Content-Type')) {
        headers.set('Content-Type', 'application/json');
      }
      requestBody = JSON.stringify(options.body);
    } else {
      requestBody = String(options.body);
    }
  }

  const timeoutMs = options?.timeoutMs ?? config.timeoutMs ?? 15000;
  let signal = options?.signal;
  let timeoutId: any = null;

  if (!signal && typeof AbortController !== 'undefined') {
    const controller = new AbortController();
    timeoutId = setTimeout(() => controller.abort(new Error('Request Timeout')), timeoutMs);
    signal = controller.signal;
  }

  const requestInit: RequestInit = {
    method,
    headers,
    body: requestBody,
    signal,
    ...options,
  };

  if (config.onRequest) {
    await config.onRequest(fullUrl, requestInit);
  }

  const fetchFn = config.customFetch || fetch;

  try {
    const response = await fetchFn(fullUrl, requestInit);
    if (config.onResponse) {
      await config.onResponse(response);
    }

    let responseData: any = null;
    if (response.status !== 204) {
      const contentType = response.headers.get('content-type') || '';
      if (contentType.includes('application/json')) {
        responseData = await response.json();
      } else {
        responseData = await response.text();
      }
    }

    if (!response.ok) {
      throw new ApiError(response.status, response.statusText, responseData, response.headers);
    }

    return responseData as T;
  } finally {
    if (timeoutId) clearTimeout(timeoutId);
  }
}

// ============================================================================
// Flagship ApiClient Class
// ============================================================================

export class ApiClient {
  private config: FetchClientConfig;

  constructor(config: FetchClientConfig = {}) {
    this.config = config;
  }

  public setBaseUrl(url: string): void {
    this.config.baseUrl = url;
  }

  public setHeaders(headers: Record<string, string>): void {
    this.config.headers = headers;
  }

  public setBearerToken(token: string): void {
    this.config.headers = { ...((typeof this.config.headers === 'object' ? this.config.headers : {})), Authorization: `Bearer ${token}` };
  }

  public setApiKey(key: string, headerName: string = 'X-API-Key'): void {
    this.config.headers = { ...((typeof this.config.headers === 'object' ? this.config.headers : {})), [headerName]: key };
  }

  /**
   * List all pets
   * @description Returns all pets from the store with optional status and tag filtering.
   * @route GET /pets
   * @param query URL search query parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async listPets(query?: ListPetsQueryParams, options?: RequestOptions): Promise<Pet[]> {
    const path = '/pets';
    return executeFetch<Pet[]>(this.config, 'GET', path, { ...options, query });
  }

  /**
   * Create a pet
   * @description Adds a new pet to the catalog.
   * @route POST /pets
   * @param body Request payload (application/json)
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async createPet(body: Pet, options?: RequestOptions): Promise<Pet> {
    const path = '/pets';
    return executeFetch<Pet>(this.config, 'POST', path, { ...options, body });
  }

  /**
   * Info for a specific pet
   * @route GET /pets/{petId}
   * @param pathParams URL path interpolation parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async getPetById(pathParams: GetPetByIdPathParams, options?: RequestOptions): Promise<Pet> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}`;
    return executeFetch<Pet>(this.config, 'GET', path, { ...options });
  }

  /**
   * Deletes a pet
   * @route DELETE /pets/{petId}
   * @param pathParams URL path interpolation parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async deletePet(pathParams: DeletePetPathParams, options?: RequestOptions): Promise<void> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}`;
    return executeFetch<void>(this.config, 'DELETE', path, { ...options });
  }

  /**
   * Uploads an image
   * @route POST /pets/{petId}/uploadImage
   * @param pathParams URL path interpolation parameters
   * @param body Request payload (multipart/form-data)
   * @param query URL search query parameters
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async uploadFile(pathParams: UploadFilePathParams, body?: {
   /** File to upload @format binary */
  file?: Blob | File | undefined;
}, query?: UploadFileQueryParams, options?: RequestOptions): Promise<ApiResponse> {
    const path = `/pets/${encodeURIComponent(String(pathParams['petId']))}/uploadImage`;
    return executeFetch<ApiResponse>(this.config, 'POST', path, { ...options, query, body });
  }

  /**
   * Returns pet inventories by status
   * @route GET /store/inventory
   * @param options Additional RequestInit options
   * @throws {ApiError}
   */
  async getInventory(options?: RequestOptions): Promise<Record<string, number>> {
    const path = '/store/inventory';
    return executeFetch<Record<string, number>>(this.config, 'GET', path, { ...options });
  }

}

api = new ApiClient();
export default ApiClient;
6
Operaciones API
4
Modelos TypeScript
9.5 KB
Tamaño Generado

Privacidad 100% en el Navegador

Sin subidas a servidores ni telemetría. Tus especificaciones API confidenciales se analizan estrictamente en la memoria del navegador.

Fetch Nativo Sin Dependencias

Genera código estándar de Web Fetch API compatible con navegadores, Node.js 18+, Bun, Deno y Next.js sin dependencias de Axios ni SDKs pesados.

Serialización y Manejo Seguro de Tipos

Interpolación automática de rutas URL, query strings con URLSearchParams, multipart FormData y manejo estructurado de errores ApiError.

Referencia técnica y guía de arquitectura

Guía del Desarrollador del Generador de Clientes TypeScript con Fetch Nativo desde OpenAPI y Swagger — Guía de referencia

Genere métodos de API en TypeScript con fetch nativo sin dependencias, serialización de consultas, cabeceras y tipos de respuesta.

Parámetros clave y controles

architecture'class' | 'functional'

Determina la arquitectura del cliente: clase orientada a objetos con configuración compartida o funciones independientes compatibles con tree-shaking.

Por defecto: 'class'
unwrapResponse'direct' | 'envelope'

Define la estructura de retorno: cuerpo de respuesta deserializado directamente (Promise<T>) o envoltorio HTTP completo ({ data, status, headers }).

Por defecto: 'direct'
includeJsdocboolean

Inserta resúmenes, descripciones y documentación de parámetros de OpenAPI como comentarios JSDoc en los métodos TypeScript.

Por defecto: true
strictNullChecksboolean

Aplica propiedades opcionales estrictas y uniones explícitas de nulos (T | null) compatibles con el modo estricto de TypeScript.

Por defecto: true
includeTimeoutboolean

Añade soporte nativo para tiempos de espera configurables en milisegundos mediante señales de AbortController.

Por defecto: true
includeMockStubsboolean

Genera datos simulados realistas e implementaciones de prueba para pruebas unitarias sin conexión y prototipado rápido.

Por defecto: false

Consejos profesionales y mejores prácticas

Seleccione la arquitectura 'SDK

Seleccione la arquitectura 'SDK Funcional' en micro-frontends o entornos serverless edge. Empaquetadores modernos como Vite, Rollup y Webpack eliminarán los métodos no utilizados mediante tree-shaking.

Pase opciones extendidas de

Pase opciones extendidas de RequestInit como next: { revalidate: 60, tags: ['items'] } o cache: 'no-store' directamente a las funciones generadas para controlar el almacenamiento en caché de Next.js.

Capture la clase tipada ApiError

Capture la clase tipada ApiError generada dentro de bloques try/catch estándar para inspeccionar códigos de estado HTTP y cargas de error sin requerir interceptores de Axios.

Errores comunes y solución de problemas

Las referencias de esquema ($ref) en definitions de Swagger 2.0 fallan

El analizador normaliza automáticamente punteros antiguos de Swagger 2.0 #/definitions/ y esquemas de OpenAPI 3.x #/components/schemas/ en interfaces TypeScript con nomenclatura PascalCase.

Los parámetros de consulta de tipo array no coinciden con el formato del backend

Ajuste la serialización de URLSearchParams según lo que requiera su backend (por ejemplo, formato con claves duplicadas o notación entre corchetes para FastAPI, Express o Django).

Errores de CORS o exclusión de cookies de autenticación en el navegador

Configure { credentials: 'include' } en el constructor del cliente o en las opciones por solicitud para permitir el envío de cookies de sesión seguras entre dominios.

Preguntas frecuentes (FAQ)

¿Por qué utilizar fetch nativo en lugar de Axios o librerías externas?▼

Fetch es un estándar web nativo presente en todos los navegadores modernos, Node.js 18+, Bun, Deno y Edge runtimes. Prescindir de Axios ahorra entre 15 y 40 KB en el bundle final y elimina vulnerabilidades en la cadena de dependencias.

¿Cómo se interpolan los parámetros de ruta y se serializan las consultas?▼

Los parámetros en la URL (p. ej. /users/{id}) se interpolan de forma segura con encodeURIComponent, mientras que los parámetros de consulta se procesan mediante URLSearchParams excluyendo automáticamente valores undefined y null.

¿Se envía mi especificación de API privada o interna a servidores externos?▼

No. Todo el análisis sintáctico de OpenAPI, recorrido del AST y generación de código TypeScript se ejecuta 100% en la memoria de su navegador web. Ningún dato sale de su equipo.

¿Puedo generar React Hooks o funciones listas para TanStack Query?▼

Sí. Cambie a la pestaña 'React Hooks' para exportar hooks personalizados y funciones fetcher perfectamente compatibles con TanStack Query (React Query) y SWR.

¿Cómo gestiona el cliente generado los errores HTTP (4xx y 5xx)?▼

Dado que fetch no rechaza promesas ante errores HTTP ordinarios, el cliente comprueba response.ok, analiza la respuesta de error JSON y lanza un ApiError tipado con código de estado y cabeceras.

Herramientas y utilidades relacionadas

Todas las herramientas →
Guía del Desarrollador del Generador de DDL SQL CREATE TABLE desde Esquemas Drizzle ORMDesarrollo

Convierta definiciones pgTable, mysqlTable y sqliteTable de Drizzle ORM en scripts de migración ejecutables SQL CREATE TABLE con total precisión.

Abrir herramienta→
Guía del generador de flujos de trabajo YAML para GitHub Actions CI/CDDesarrollo

Cree canalizaciones de flujos de trabajo YAML de GitHub Actions listas para producción para Node.js, Go, Python, compilaciones de Docker, pruebas y lanzamientos automatizados.

Abrir herramienta→
Generador de Configuraciones Linux Logrotate (Retención y Compresión)Desarrollo

Genere archivos de configuración para /etc/logrotate.d/ listos para producción con rotación diaria/semanal, compresión gzip, dateext, límites de tamaño y scripts postrotate.

Abrir herramienta→
Guía de Desarrollo del Generador de Configuración YAML de Ubuntu NetplanDesarrollo

Genere configuraciones netplan YAML para Ubuntu 20.04/22.04/24.04: IPs estáticas, DHCP, servidores DNS, rutas de puerta de enlace, bridges y bonds.

Abrir herramienta→
Guía de Desarrollo: Generador de Modelos Python SQLAlchemy 2.0 desde SQL DDLDesarrollo

Convierta sentencias SQL CREATE TABLE en modelos fuertemente tipados de Python SQLAlchemy 2.0 DeclarativeBase con anotaciones Mapped y mapped_column.

Abrir herramienta→
Guía para Desarrolladores: Generador de Modelos Struct GORM para Golang desde SQL DDLDesarrollo

Convierta esquemas SQL CREATE TABLE en definiciones de estructuras struct de Golang con etiquetas GORM, etiquetas JSON y tipos Go fuertemente tipados.

Abrir herramienta→