npm package: @skielder/mockas
Description: A simple and fast mocking api server
Author: Bruno
Latest version: 1.0.2


# Mockas - API Mocking Library
![Mockas Logo](https://raw.githubusercontent.com/skielder/mockas/refs/heads/master/Logo.svg)

Mockas is a simple and flexible library for mocking APIs in Node.js and the browser. It allows defining routes, generating dummy data, simulating authentication, and intercepting fetch requests.

## Features

- **Fluent API**: Define routes and responses intuitively.
- **Node.js & Browser**: Works server-side (e.g., with Express) and client-side (by intercepting fetch).
- **Static & Dynamic Responses**: Return fixed data or use handler functions for dynamic logic.
- **Path Parameters**: Supports routes like `/users/:id`.
- **Delay Simulation**: Add artificial latency to responses.
- **Authentication**: Simple setup for token-based authentication (Bearer token) and login routes.
- **Data Generation**: Create dummy data (users, posts, etc.) based on schemas.
- **Automatic API Generation**: Create complete RESTful APIs for resources with just a few lines of configuration.
- **Fetch Interception**: Replace `window.fetch` in the browser to intercept requests.
- **Middleware**: Easily integrate Mockas into Express/Connect applications.

## Installation

```bash
npm install @skielder/mockas
# or
yarn add @skielder/mockas
```

## Basic Usage
### Import Mockas
```js
// Import (Node.js)
const Mockas = require('mockas');
```

### Create a Mockas Instance

```js
const mockas = new Mockas({
  delay: 50,  // Optional global delay of 50ms
  baseUrl: '/api/v1'  // Optional: Removes '/api/v1' from the path before matching
});
```


### Define Routes
```js
// Static response
mockas.get('/users')
  .willReturn([
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ]);

// Dynamic response
mockas.get('/users/:id')
  .withHandler((requestData) => {
    const userId = parseInt(requestData.params.id, 10);
    if (userId === 1) {
      return { id: 1, name: 'Alice', email: 'alice@example.com' };
    }
    return { status: 404, data: { error: 'User not found' } };
  });

// POST route with status and delay
mockas.post('/users')
  .withStatus(201)
  .withDelay(100)
  .withHandler((requestData) => {
    console.log('Received new user data:', requestData);
    const newUser = { ...requestData, id: Date.now() };
    delete newUser.query;
    delete newUser.params;
    return newUser;
  });
```
### Use Mockas
#### Option A: Intercept global Fetch (Browser)

```js
if (typeof window !== 'undefined') {
  mockas.installGlobalFetch();

  fetch('/api/v1/users')
    .then(res => res.json())
    .then(console.log);

  fetch('/api/v1/users/1')
    .then(res => res.json())
    .then(console.log);

  // Clean up later:
  // mockas.uninstallGlobalFetch();
}
```
#### Option B: Manual Requests (Node.js)

```js
async function runManualRequest() {
  const response = await mockas.request('GET', '/users');
  console.log('Manual request response:', response);

  const notFound = await mockas.request('GET', '/users/99');
  console.log('Manual not found:', notFound);
}

if (typeof window === 'undefined') {
  runManualRequest();
}
```

#### Option C: As Middleware (Node.js with Express/Connect)

```js
const express = require('express');

const Mockas = require('mockas');

const app = express();

const port = 3000;

const mockas = new Mockas({
	baseUrl:  '/api', // Optional: prefix for mock routes
	delay:  50, // Optional: Global delay
});

mockas.get('/api/hello')
	.willReturn({ message:  'Hello from Mocka!' })
	.register();

mockas.get('/api/users')
	.willReturn([
		{ id:  1, name:  'Alice' },
		{ id:  2, name:  'Bob' }
	])
	.withStatus(200)
	.register();

mockas.get('/api/users/:id')
	.withHandler((reqData) => {
		  const  userId  =  parseInt(reqData.params.id, 10);
		  if (userId  ===  1) return { id:  1, name:  'Alice', details:  'Found user 1' };
		  if (userId  ===  2) return { id:  2, name:  'Bob', details:  'Found user 2' };
		  return { error:  'User not found' };
	})
	.register();

mockas.post('/api/echo')
	.withHandler((reqData) => {
	  console.log('Received data in /api/echo:', reqData);
		return { received:  reqData };
	})
	.withStatus(201)
	.register();

app.use(express.json());

app.use(express.urlencoded({ extended: true }));

app.use(Mockas.middleware(mockas));

app.get('/real-api/status', (req, res) => {
	res.json({ status:  'Real API endpoint is active!' });
}); 

app.use((req, res) => {
	res.status(404).json({ error:  'Not Found (Express Fallback)' });
});

app.listen(port, () => {
	console.log(`Express server with Mockas running at http://localhost:${port}`);
});
```

## Core Concepts
### Defining Routes

Use the HTTP methods (`get`, `post`, `put`, `patch`, `delete`) on the Mockas instance to start defining a route:
```js
mockas.get('/path');
mockas.post('/path');
// ... etc
```
### Configuring Responses

#### Static Response
```js
mockas.get('/notfound').withStatus(404).willReturn({ error: 'Not Found' });
```
#### Dynamic Response
```js
mockas.get('/items')
  .withHandler((reqData) => {
    const filter = reqData.query.filter;
    const items = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];
    if (filter) {
      return items.filter(item => item.name.includes(filter));
    }
    return items;
  });
```

#### Response Headers
```js
mockas.get('/cached-data')
  .withResponseHeaders({ 'Cache-Control': 'max-age=3600' })
  .willReturn({ data: '...' });
```

#### Delay Simulation

```js
mockas.get('/slow-resource').withDelay(1500).willReturn({ done: true });
```
#### Authentication
```js
mockas.get('/admin/data').expectAuth().willReturn({ secret: 'data' });
```
#### Path Parameters
```js
mockas.get('/products/:category/:productId')
  .withHandler((reqData) => {
    const { category, productId } = reqData.params;
    return { info: `Details for product ${productId} in category ${category}` };
  });
```
#### Authentication
Mockas supports simple token-based authentication using `setupAuth`:
```js
mockas.setupAuth({
  tokenKey: 'Authorization',
  tokenValue: 'Bearer ',
  users: [
    { id: 1, username: 'claude', password: 'password123', role: 'admin' }
  ],
  autoCreateLoginRoute: true
});
```
To protect routes:
```js
mockas.get('/secure/resource').expectAuth().willReturn({ data: 'secret' });
```
### Generating Dummy Data
Use `createDummyData` to generate test data based on a schema:
```js
const postSchema = {
  id: { type: 'increment', start: 1 },
  userId: { type: 'randomInt', min: 1, max: 10 },
  title: (ctx) => `Post ${ctx.currentItem.id}`,
  body: { type: 'lorem', words: 30 },
  tags: ['news', 'tech', 'code'],
  publishedAt: { type: 'date' }
};

const posts = mockas.createDummyData(postSchema, 5);
console.log(posts);
```

### Automatic API Generation
```js
const managedUsers = mockas.createUserAPI(); // Creates /users, /users/:id etc.
const managedProfiles = mockas.createUserAPI('/profiles', [], true); // Authentication for all routes
```

### Fetch Interception (Browser)
```js
mockas.installGlobalFetch();
```

### Middleware (Node.js)
```js
app.use(Mockas.middleware(mockasInstance));
```
## License

Mockas is an open-source library released under the [MIT License](https://opensource.org/licenses/MIT).

## Reporting Issues

If you encounter any issues or bugs while using Mockas, please feel free to open an issue on our [GitHub repository](https://github.com/skielder/mockas/issues). We appreciate your feedback and contributions to improve the library!

Thank you for using Mockas!