Mock API

Documentation for Public

Mock API Title

Librería para interceptar y simular llamadas a REST APIs durante el desarrollo con Angular 20. Ofrece configuración flexible, middleware, utilidades de datos y compatibilidad total con RxJS.

🚀 Características

📦 Instalación

# Si estás en el workspace
yarn install

# Para uso externo (cuando se publique)
yarn add @mock-api

🔧 Configuración Rápida

1) app.config.ts

import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import {
  mockHttpInterceptor,
  MockInterceptorUtilsService,
  MiddlewareFactory,
} from '@mock-api';
import { environment } from '../environments/environment';
import { UsersMock } from '@mock-api';

export const appConfig: ApplicationConfig = {
  providers: [
    // 1) Registrar el interceptor
    provideHttpClient(withInterceptors([mockHttpInterceptor])),

    // 2) Configurar el interceptor y los mocks al iniciar la app
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [MockInterceptorUtilsService],
      useFactory: (utils: MockInterceptorUtilsService) => () => {
        utils.configureMockInterceptor(
          {
            enabled: !environment.production,
            delay: [100, 300],
            fallbackToNetwork: true,
            logging: { enabled: true, level: 'info', logRequests: true, logResponses: true },
            persistence: { enabled: false, ttl: 300000, storage: 'memory' },
            routeMatching: { normalizeURLs: true, supportWildcards: true },
            defaultHeaders: { 'Content-Type': 'application/json' },
            middleware: [
              MiddlewareFactory.createLoggingMiddleware(),
              MiddlewareFactory.createCorsMiddleware(),
            ],
          },
          {
            ...UsersMock,
            // Puedes combinar múltiples objetos de mocks aquí
          }
        );
        return Promise.resolve();
      },
    },
  ],
};

2. Usar en tus servicios:

import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class UserService {
  private http = inject(HttpClient);

  getUsers() {
    // Esta llamada será interceptada por el mock en desarrollo
    return this.http.get('/api/users');
  }

  getUser(id: string) {
    return this.http.get(`/api/users/${id}`);
  }

  createUser(user: any) {
    return this.http.post('/api/users', user);
  }
}

📋 Definición de Mocks

Ejemplo básico:

import { MockDefinition, MockRequest, MockResponse } from '@mock-api';

export const UsersMock: MockDefinition = {
  'GET /api/users': (req: MockRequest): MockResponse => ({
    status: 200,
    data: [
      { id: 1, name: 'Juan Pérez', email: '[email protected]' },
      { id: 2, name: 'María García', email: '[email protected]' },
    ],
  }),

  'GET /api/users/:id': (req: MockRequest): MockResponse => ({
    status: 200,
    data: {
      id: req.params.id,
      name: 'Usuario',
      email: '[email protected]',
    },
  }),

  'POST /api/users': (req: MockRequest): MockResponse => ({
    status: 201,
    data: { ...req.body, id: Date.now() },
    headers: { Location: `/api/users/${Date.now()}` },
  }),
};

Con generación de datos:

import { DataGenerator, MockDefinition, MockRequest, MockResponse } from '@mock-api';

const generator = DataGenerator.getInstance();

export const ProductsMock: MockDefinition = {
  'GET /api/products': (req: MockRequest): MockResponse => {
    const page = parseInt(req.query.page || '1');
    const limit = parseInt(req.query.limit || '10');

    const products = generator.generateArray(() => generator.generateProduct(), limit);

    return {
      status: 200,
      data: {
        products,
        pagination: { page, limit, total: 100 },
      },
      delay: 200, // Delay específico para esta ruta
    };
  },
};

🏗️ Configuración Avanzada

Actualizar mocks dinámicamente (en runtime)

import { Component, inject } from '@angular/core';
import { MockInterceptorUtilsService, MockDefinition } from '@mock-api';

@Component({
  selector: 'app-demo',
  template: `<button (click)="enableDemoData()">Demo Data</button>`,
  standalone: true,
})
export class DemoComponent {
  private mockUtils = inject(MockInterceptorUtilsService);

  enableDemoData() {
    const extraMocks: MockDefinition = {
      'GET /api/feature/flags': () => ({ status: 200, data: { newHeader: true } }),
    };
    this.mockUtils.updateMocks(extraMocks);
  }
}

Middleware personalizado

import { MockMiddleware, MiddlewareFactory } from '@mock-api';

// 1) Con la factory integrada
const logging = MiddlewareFactory.createLoggingMiddleware({
  logRequests: true,
  logResponses: true,
});
const cors = MiddlewareFactory.createCorsMiddleware({ origin: '*', credentials: true });

// 2) Middleware custom
const authMiddleware: MockMiddleware = {
  name: 'auth',
  priority: 800,
  onRequest: request => {
    request.headers['Authorization'] = request.headers['Authorization'] || 'Bearer mock-token';
    return request;
  },
  onResponse: (response, request) => {
    return {
      ...response,
      headers: { ...response.headers, 'X-Mock-User': 'mock-user' },
    };
  },
};

// Registrar en la configuración global (ver app.config.ts)

🔧 API Reference

Tipos principales

// Request
interface MockRequest {
  method: string;
  url: string;
  params: Record<string, string>;
  query: Record<string, string>;
  body: any;
  headers: Record<string, string>;
  timestamp?: number;
  requestId?: string;
}

// Response
interface MockResponse {
  status: number;
  data: any;
  headers?: Record<string, string>;
  delay?: number;
  statusText?: string;
}

// Definiciones
type MockHandler = (
  req: MockRequest
) => MockResponse | Promise<MockResponse> | Observable<MockResponse>;
type MockDefinition = Record<string, MockHandler>;

// Configuración del interceptor
interface GlobalInterceptorConfig {
  enabled: boolean;
  baseURL?: string;
  delay?: number | [number, number];
  persistence?: {
    enabled: boolean;
    ttl?: number;
    storage?: 'indexeddb' | 'localstorage' | 'memory';
    dbName?: string;
    dbVersion?: number;
    storeName?: string;
    maxCacheSize?: number;
    autoCleanup?: boolean;
  };
  middleware?: MockMiddleware[];
  fallbackToNetwork?: boolean;
  logging?: {
    enabled: boolean;
    level: 'debug' | 'info' | 'warn' | 'error';
    logRequests?: boolean;
    logResponses?: boolean;
    logRouteMatching?: boolean;
    logCacheOperations?: boolean;
  };
  routeMatching?: {
    caseSensitive?: boolean;
    exactMatch?: boolean;
    stripPrefix?: string;
    normalizeURLs?: boolean;
    parameterPrefix?: string;
    supportWildcards?: boolean;
  };
  defaultHeaders?: Record<string, string>;
  preserveOriginalHeaders?: boolean;
  ignorePatterns?: (string | RegExp)[];
  includePatterns?: (string | RegExp)[];
}

Utilidades

import { DataGenerator, MockValidator, RouteMatcher } from '@mock-api';

// Generador de datos
const generator = DataGenerator.getInstance();
const user = generator.generateUser();
const products = generator.generateArray(() => generator.generateProduct(), 10);

// Validación
const validation = MockValidator.validateMockDefinitions(myMocks);
if (!validation.isValid) {
  console.error('Mocks inválidos:', validation.errors);
}

// Matching de rutas
const matcher = new RouteMatcher();
const result = matcher.match('GET /api/users/:id', '/api/users/123', 'GET');

🎯 Casos de Uso

1. Desarrollo Frontend sin Backend

// Simular toda la API mientras se desarrolla el frontend
const fullAPIMocks = {
  'GET /api/users': () => ({ status: 200, data: users }),
  'POST /api/users': req => ({ status: 201, data: { ...req.body, id: newId() } }),
  'GET /api/products': () => ({ status: 200, data: products }),
  // ... más endpoints
};

2. Testing E2E / Unit

// Mocks mínimos y predecibles para tests
const testingMocks = {
  'GET /api/users/1': () => ({
    status: 200,
    data: { id: 1, name: 'Test User' },
  }),
};

3. Demos y Presentaciones

// Datos atractivos con delays realistas
setupMockAPI(demoRegistry, {
  delay: [500, 1000], // Delays más largos para efectos visuales
  enableLogging: true,
});

🐛 Debugging

import { inject } from '@angular/core';
import { MockInterceptorUtilsService, MockInterceptorConfig } from '@mock-api';

const utils = inject(MockInterceptorUtilsService);
const config = inject(MockInterceptorConfig);

// Toggle manual
config.setEnabled(false);
config.setEnabled(true);

// Ver estadísticas
console.log('Stats:', utils.getStats());

// Limpiar mocks
utils.clearMocks();

🔧 Configuración Detallada

Opciones de persistencia

const config: GlobalInterceptorConfig = {
  enabled: true,
  persistence: {
    enabled: true,
    ttl: 300000, // 5 minutos
    storage: 'indexeddb',
    dbName: 'mock-api-db',
    storeName: 'responses',
    autoCleanup: true,
  },
};
// utils.configureMockInterceptor(config, mocks)

Configuración de red

const config: GlobalInterceptorConfig = {
  enabled: true,
  fallbackToNetwork: true,
  delay: [100, 500],
  routeMatching: { stripPrefix: '/api', normalizeURLs: true },
};