Project Awesome project awesome

ngx-api-mocks-interceptor

A powerful Angular HTTP interceptor for mocking API responses with support for dynamic data generation, path matching, response delays, and simulated file operations.

Package 2 stars GitHub

Ngx API Mock Interceptor

npm version npm downloads CI Quality License Angular Version

A powerful HTTP mock interceptor for Angular applications that helps you simulate API responses during development and testing.

🔥 Live Demo

Features

  • 🚀 Easy to set up and use
  • 🎯 Path matching with typed parameters support
  • 📝 Query parameters and headers matching
  • ⏱️ Configurable response delays
  • 🔄 Counter-based responses
  • 🎮 Full control over mock responses
  • 📦 Mock data factory
  • 🔄 Progress events simulation
  • 📁 File download simulation

Installation

npm i ngx-api-mocks-interceptor

Quick Start

  1. Create and Import the interceptor in your app.config.ts:
ng g interceptor mockInterceptor
import { HttpInterceptorFn } from "@angular/common/http";

export const mockInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req);
};

export const appConfig: ApplicationConfig = {
  providers: [provideHttpClient(withInterceptors([mockInterceptor]))],
};
  1. Create your mock data using the factory:
import { autoIncrement, boolean, mocks, lorem, array, literal } from "ngx-api-mocks-interceptor";
import { faker } from "@faker-js/faker";

interface Todo {
  id: number;
  label: string;
  description: string;
  completed: boolean;
  status: 'OPEN' | 'CLOSE' | 'WAITING';
  options: {
    id: number;
    name: string;
  }[];
}

// Create several mocks with the `mocks` factory
export const todosMock = mocks<Todo>(
  {
    id: autoIncrement(1),
    label: () => faker.lorem.words(3), // We can use faker or any other generator
    description: lorem(6),
    completed: boolean(0.3),
    status: literal(['OPEN', 'CLOSE', 'WAITING'])
    options: array({
      id: autoIncrement(1),
      name: value('foo'),
    }, {count: 2}),
  },
  {
    count: 10, // Generate 10 items
  }
);

// Or a single mock with the `mock` factory
export const todoMock = mock<Todo>({
  id: autoIncrement(1),
  label: () => faker.lorem.words(3),
  description: lorem(6),
  completed: boolean(0.3),
  status: literal(['OPEN', 'WAITING'])
  options: array({
    id: autoIncrement(1),
    name: value('foo'),
  }, { min: 2, max: 5 }),
});
  1. Configure your mock interceptor:
import { match, mockRouter } from "ngx-api-mocks-interceptor";

export const mockInterceptor: HttpInterceptorFn = (req, next) => {
  const endpoint = "http://localhost:3000/api/v1";

  return mockRouter(req, next, {
    delay: 1000,
    pathMatch: "full",
    routes: [
      match(`${endpoint}/api/todos/`, "GET", () => new HttpResponse({ status: 200, body: todosMock.value })),
      match(`${endpoint}/api/todos/:id`, "GET", (_, params) => {
        const todo = todosMock.get((todo) => todo.id === +params.id);
        return new HttpResponse({ status: 200, body: todo });
      }),
      match(
        `${endpoint}/api/todos`,
        "POST",
        (req: HttpRequest<Partial<Todo>>) =>
          new HttpResponse({
            status: 201,
            body: todosMock.add(req.body!),
          })
      ),
    ],
    // Handle unmatched routes
    onNoMatch: () => of(new HttpResponse({ status: 404, body: { error: "Not Found" } })),
  });
};
  1. Advenced configuration:
import { createRouteCounter, match, mockRouter, createFileMockResponse } from "ngx-api-mocks-interceptor";

const getItemCounter = createRouteCounter();
export const mockInterceptor: HttpInterceptorFn = (req, next) => {
  const endpoint = "http://localhost:3000/api/v1";

  return mockRouter(req, next, {
    delay: 1000, // Global delay
    pathMatch: "full",
    routes: [
      match(
        `${endpoint}/api/todos`,
        "GET",
        () =>
          new HttpResponse({
            status: 200,
            body: todosMock.value,
          }),
        {
          delay: 800,
          counter: getItemCounter,
          responses: [
            {
              count: "2n", // Every second request
              response: () =>
                new HttpResponse({
                  status: 429,
                  body: { error: "Rate limited" },
                }),
            },
            {
              count: ">5", // After 5 requests
              response: () =>
                new HttpResponse({
                  status: 503,
                  body: { error: "Service degraded" },
                }),
            },
          ],
        }
      ),

      // GET with path parameters
      match(`${endpoint}/api/todos/:id`, "GET", (_, params) => {
        const todo = todosMock.get((todo) => todo.id === +params.id);
        return new HttpResponse({ status: 200, body: todo });
      }),

      // POST with request body
      match(
        `${endpoint}/api/todos`,
        "POST",
        (req: HttpRequest<Partial<Todo>>) =>
          new HttpResponse({
            status: 201,
            body: todosMock.add(req.body!),
          })
      ),

      // File download simulation
      match(`${endpoint}/api/todos/download`, "GET", () =>
        createFileMockResponse({
          path: "/mocks/example.txt",
          filename: "todos.txt",
          contentType: "text/plain",
          headers: {
            "Cache-Control": "no-cache",
          },
          chunkDelay: 200,
        })
      ),

      // Upload progress simulation
      match(`${endpoint}/api/upload`, "POST", () => [
        {
          type: HttpEventType.UploadProgress,
          loaded: 0,
          total: 100,
        },
        {
          type: HttpEventType.UploadProgress,
          loaded: 50,
          total: 100,
        },
        new HttpResponse({
          status: 200,
          body: { message: "Upload complete" },
        }),
      ]),
    ],
    // Handle unmatched routes
    onNoMatch: () =>
      of(
        new HttpResponse({
          status: 404,
          body: { error: "Not Found" },
        })
      ),
  });
};

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Back to Angular