Building a Mock REST Server with TypeScript, Faker, Fakerest, and MSW
Introduction: The Power of Mock Servers in Modern Development
In todayโs fast-paced development environment, waiting for backend APIs to be ready can significantly slow down frontend development. This is where mock servers become invaluable tools that can accelerate your development workflow and improve team productivity.
A mock server is essentially a simulator that mimics the behavior of a real backend API. It allows you to create realistic API responses without having a fully implemented backend, enabling parallel development workflows and reducing dependencies between frontend and backend teams.
What is a Mock Server?
A mock server is a tool or service that simulates the behavior of a real backend API. Instead of waiting for the backend to be ready, you can use a mock server to return fake or predefined responses to your frontend application. This allows you to develop, test, and demo your frontend independently of the backend.
Benefits of Using a Mock Server
- Faster Frontend Development: Start building and testing your UI before the backend is ready.
- Parallel Workflows: Frontend and backend teams can work independently, reducing bottlenecks.
- Consistent, Realistic Data: Use fake but realistic data for demos, tests, and development.
- Reliable Testing: Write frontend tests that donโt depend on backend availability or state.
- Rapid Prototyping: Quickly try new ideas and iterate on features.
- Stakeholder Demos: Show off features with live, interactive data.
- Onboarding: New team members can get started without waiting for backend access.
- Cost Efficiency: Reduce development time and resource allocation conflicts.
- Risk Mitigation: Test edge cases and error scenarios easily.
What is the fakerest (FakeRest) Library?
FakeRest is a powerful open source library that automatically transforms your JavaScript data into a fully functional mock REST API. This library is particularly valuable for frontend developers who need to simulate backend functionality without writing complex server code.
Key Features of FakeRest:
- Automatic REST Endpoint Generation: Get REST endpoints (GET, POST, PUT, DELETE) for any data collection without writing backend code.
- Advanced Query Support: Built-in support for filtering, sorting, pagination, and embedding related resources.
- Flexible Data Sources: Works seamlessly with fake data from faker, static data, or your own generated data.
- Development Versatility: Perfect for prototyping, demos, frontend testing, and parallel frontend-backend development.
- Multiple Integration Options: Easy integration with Express (Node.js) and provides handlers for MSW (Mock Service Worker).
- Real-world API Behavior: Simulates realistic API responses including proper HTTP status codes and headers.
Why Choose FakeRest?
FakeRest eliminates the complexity of setting up a full backend server while providing enterprise-grade API functionality. Itโs particularly useful when you need to demonstrate complex data relationships and advanced query capabilities to stakeholders or during development phases.
What is MSW (Mock Service Worker)?
Mock Service Worker is a revolutionary library that represents the next generation of API mocking. Unlike traditional mocking approaches that require you to modify your application code, MSW intercepts network requests at the browserโs network level, making your mocks virtually indistinguishable from real API calls.
Key Features of MSW:
- Network-Level Interception: Intercepts fetch/XHR requests in the browser and returns mock responses based on your handlers without modifying application code.
- Cross-Platform Support: Can be used in Node.js for automated testing (Jest, Vitest, Playwright, etc.) and in browsers for development.
- Seamless Integration: Handlers can be written manually for fine-grained control or generated automatically from FakeRest for consistency.
- Framework Agnostic: Works perfectly with React, Vue, Svelte, Angular, and any other modern framework.
- Development & Testing: Supports both development workflows and comprehensive testing strategies.
- Real Network Behavior: Simulates actual network conditions including latency, errors, and edge cases.
Why MSW is Game-Changing:
MSW eliminates the traditional problem of โmocking vs. real APIโ discrepancies. Since it operates at the network level, your application code remains unchanged whether itโs hitting mock endpoints or real APIs. This ensures that your tests and development environment closely mirror production behavior.
Use Cases:
- Development: Develop frontend features without waiting for backend APIs
- Testing: Create reliable, deterministic tests that donโt depend on external services
- Edge Case Testing: Simulate network failures, slow responses, and error conditions
- Demo Environments: Provide consistent, controlled data for stakeholder presentations
Step-by-Step: Creating a TypeScript Mock Server Project
1. Initialize the Project
mkdir fake-rest
cd fake-rest
npm init -y
2. Install Dependencies
npm install express fakerest @faker-js/faker msw date-fns
npm install -D typescript ts-node @types/node @types/express prettier
3. Set Up TypeScript
Create a tsconfig.json:
{
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"types": ["node"],
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"strict": true,
"noImplicitAny": false,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true
}
}
4. Project Structure
fake-rest/
โโโ package.json
โโโ tsconfig.json
โโโ README.md
โโโ src/
โ โโโ dataGenerator/
โ โ โโโ index.ts
โ โ โโโ customer.ts
โ โ โโโ products.ts
โ โ โโโ ...
โ โโโ fakeServer/
โ โ โโโ express.ts
โ โ โโโ index.ts
โ โ โโโ ...
โ โโโ server.ts
โ โโโ demo.ts
โโโ ...
dataGenerator/: Functions to generate fake data for each collection (customers, products, etc.)fakeServer/: Code to set up the mock serverserver.ts: Entry point to start the Express serverdemo.ts: Script to demo/test the API
5. Generate Fake Data with Faker
Faker is a powerful library for generating realistic fake data. It provides a wide variety of data types and locales, making it perfect for creating convincing mock APIs.
Example: src/dataGenerator/customer.ts
import { faker } from "@faker-js/faker";
export function generateCustomers(count: number = 50) {
return Array.from({ length: count }).map((_, index) => ({
id: faker.string.uuid(),
first_name: faker.person.firstName(),
last_name: faker.person.lastName(),
email: faker.internet.email(),
phone: faker.phone.number(),
address: {
street: faker.location.streetAddress(),
city: faker.location.city(),
country: faker.location.country(),
zipCode: faker.location.zipCode(),
},
company: faker.company.name(),
job_title: faker.person.jobTitle(),
avatar: faker.image.avatar(),
created_at: faker.date.past({ years: 2 }),
updated_at: faker.date.recent({ days: 30 }),
is_active: faker.datatype.boolean(0.8), // 80% chance of being active
subscription_tier: faker.helpers.arrayElement([
"free",
"premium",
"enterprise",
]),
}));
}
Example: src/dataGenerator/products.ts
import { faker } from "@faker-js/faker";
export function generateProducts(count: number = 100) {
return Array.from({ length: count }).map((_, index) => ({
id: faker.string.uuid(),
name: faker.commerce.productName(),
description: faker.commerce.productDescription(),
price: parseFloat(faker.commerce.price({ min: 10, max: 1000, dec: 2 })),
category: faker.commerce.department(),
brand: faker.company.name(),
sku: faker.string.alphanumeric(8).toUpperCase(),
stock: faker.number.int({ min: 0, max: 100 }),
images: Array.from({ length: faker.number.int({ min: 1, max: 5 }) }).map(
() => faker.image.url({ width: 800, height: 600 }),
),
rating: faker.number.float({ min: 1, max: 5, fractionDigits: 1 }),
reviews_count: faker.number.int({ min: 0, max: 500 }),
tags: faker.helpers.arrayElements(
["electronics", "clothing", "books", "home", "sports", "beauty", "toys"],
{ min: 1, max: 3 },
),
is_featured: faker.datatype.boolean(0.2), // 20% chance of being featured
created_at: faker.date.past({ years: 1 }),
updated_at: faker.date.recent({ days: 7 }),
}));
}
Combine all generators in src/dataGenerator/index.ts:
import type { Db } from "./types.js";
import { generateCustomers } from "./customer.js";
import { generateCategories } from "./categories.js";
import { generateProducts } from "./products.js";
import { generateOrders } from "./orders.js";
import { generateInvoices } from "./invoices.js";
import { generateReviews } from "./reviews.js";
import finalize from "./finalize.js";
const generateData = (): Db => {
console.log("Generating demo data...");
const db = {} as Db;
db.customers = generateCustomers();
db.categories = generateCategories();
db.products = generateProducts(db);
db.orders = generateOrders(db);
db.invoices = generateInvoices(db);
db.reviews = generateReviews(db);
finalize(db);
return db as Db;
};
export default generateData;
6. Set Up the Express Mock Server
Example: src/fakeServer/express.ts
import express from "express";
import { SimpleRestServer } from "fakerest";
import generateData from "../dataGenerator";
export default () => {
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const data = generateData();
const restServer = new SimpleRestServer({ data, loggingEnabled: true });
app.use("/", async (req, res) => {
// Parse filter, sort, range, embed as JSON if present
const params = { ...req.query };
["filter", "sort", "range", "embed"].forEach((key) => {
if (typeof params[key] === "string") {
try {
params[key] = JSON.parse(params[key]);
} catch {}
}
});
const context = {
method: req.method,
url: req.url,
requestBody: req.body,
headers: new Headers(),
params,
};
const response = await restServer.handle(context);
if (response.headers)
Object.entries(response.headers).forEach(([k, v]) => res.setHeader(k, v));
res.status(response.status).json(response.body);
});
return app;
};
7. Start the Server
Example: src/server.ts
import createExpressApp from "./fakeServer/express";
const app = createExpressApp();
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Mock server running at http://localhost:${PORT}`);
});
Run with:
npm run start
8. Use Advanced API Features
- Filtering:
curl 'http://localhost:3000/customers?filter=%7B%22first_name%22%3A%22Bruce%22%7D' - Sorting:
curl 'http://localhost:3000/products?sort=%5B%22price%22%2C%22desc%22%5D' - Embedding:
curl 'http://localhost:3000/orders?embed=%5B%22customer%22%5D'
9. Mocking APIs in the Browser or Tests with MSW
Browser Example:
import { setupWorker } from "msw/browser";
import { getMswHandler } from "fakerest";
import generateData from "./dataGenerator";
const handler = getMswHandler({ baseUrl: "/api", data: generateData() });
const worker = setupWorker(handler);
worker.start();
Node.js Example (for tests):
import { setupServer } from "msw/node";
import { getMswHandler } from "fakerest";
import generateData from "./dataGenerator";
const handler = getMswHandler({ baseUrl: "/api", data: generateData() });
const server = setupServer(handler);
server.listen();
Summary: Why This Approach Rocks
- No backend required: Start building and testing immediately.
- Realistic, flexible data: Use faker for believable, varied data.
- Powerful API features: Filtering, sorting, pagination, and embedding out of the box.
- Works everywhere: Node.js, browser, and automated tests.
- Easy to extend: Add new collections or fields as your prototype grows.
Note: The code in this article is adapted and inspired by the master example from the marmelab repository.
Repository: github.com/kreasipositif/fake-rest
Ready to master modern architecture? Join our comprehensive development courses at Kreasi Positif Indonesia and learn industry best practices from experienced software engineers.