Skip to content

Commit e52fbe6

Browse files
Add API prefix support for routes and middleware
- Introduced `--enable-api-prefix` option for CLI and programmatic usage - Implemented `apiPrefixMiddleware` to handle `/api/*` routing - Updated documentation to reflect new API prefix feature - Modified relevant tests to include API prefix scenarios
1 parent 83985c0 commit e52fbe6

File tree

11 files changed

+247
-7
lines changed

11 files changed

+247
-7
lines changed

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ A TypeScript implementation of json-server with additional features and comprehe
1111
- Full TypeScript support with type definitions
1212
- RESTful API endpoints from a JSON file or JavaScript object
1313
- Configurable routes
14+
- API prefix support (`/api/*` for all routes)
1415
- Support for multiple package managers (npm, yarn, pnpm, bun)
1516
- CORS support
1617
- Delay simulation for network latency testing
@@ -178,6 +179,7 @@ Options:
178179
--read-only, --ro Allow only GET requests [default: false]
179180
--no-cors, --nc Disable CORS [default: false]
180181
--no-gzip, --ng Disable GZIP compression [default: false]
182+
--enable-api-prefix, --api Enable /api/* prefix [default: false]
181183
--delay, -d Add delay to responses (ms) [number]
182184
--id, -i Set database id field [default: "id"]
183185
--foreignKeySuffix Set foreign key suffix [default: "_id"]
@@ -203,6 +205,50 @@ GET /posts?_sort=title&_order=asc
203205
GET /posts?_sort=title&_order=desc
204206
```
205207

208+
## API Prefix
209+
210+
The API prefix feature allows you to access all your resources with an `/api` prefix. This is useful when:
211+
212+
- You want to make your mock API feel more like a real backend
213+
- You need to differentiate API routes from other routes in your application
214+
- You're working with frontend frameworks that expect API routes to start with `/api`
215+
216+
### Using API Prefix with CLI
217+
218+
Enable the API prefix feature using the `--enable-api-prefix` (or `-api` shorthand) flag:
219+
220+
```bash
221+
json-server db.json --enable-api-prefix
222+
```
223+
224+
This allows you to access resources through both standard and API-prefixed routes:
225+
226+
```
227+
# Standard routes still work
228+
GET /posts
229+
GET /posts/1
230+
231+
# API-prefixed routes also work
232+
GET /api/posts
233+
GET /api/posts/1
234+
```
235+
236+
### Using API Prefix Programmatically
237+
238+
```typescript
239+
import { create } from '@webmasterdevlin/json-server';
240+
241+
const server = create({
242+
port: 3000,
243+
enableApiPrefix: true, // Enable the API prefix feature
244+
});
245+
246+
server.loadDatabase('./db.json');
247+
server.start().then(() => {
248+
console.log('Server running with API prefix support');
249+
});
250+
```
251+
206252
## Programmatic Usage
207253

208254
```typescript
@@ -220,6 +266,7 @@ const server = create({
220266
host: 'localhost',
221267
readOnly: false, // Allow all HTTP methods
222268
delay: 1000, // Add 1s delay to responses
269+
enableApiPrefix: true, // Enable /api/* prefix for all routes
223270
});
224271

225272
// Create a custom route

mod.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44
* This module provides a Deno-compatible interface for json-server.
55
* It can be used both as a CLI and as a programmatic API from Deno scripts.
66
*
7+
* Features include:
8+
* - TypeScript-powered JSON Server with API prefix support
9+
* - RESTful API with custom routes
10+
* - Configurable settings for CORS, delay, read-only mode
11+
* - API prefix (/api/*) routing via the enableApiPrefix option
12+
*
713
* @example
814
* // Run from command line:
9-
* // deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json --port 3001
15+
* // deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json --port 3001 --enable-api-prefix
1016
*
1117
* // Import programmatically:
1218
* // import { create } from "./mod.ts";
13-
* // const server = create({ port: 3000 });
19+
* // const server = create({ port: 3000, enableApiPrefix: true });
1420
* // server.loadDatabase("./db.json");
1521
* // await server.start();
1622
*
@@ -43,6 +49,7 @@ Options:
4349
--id, -i Set database id field [default: "id"]
4450
--read-only, --ro Allow only GET requests [default: false]
4551
--no-cors, --nc Disable CORS [default: false]
52+
--enable-api-prefix, --api Enable /api/* prefix [default: false]
4653
--quiet, -q Suppress log messages [default: false]
4754
--help, -h Show help [boolean]
4855
--version, -v Show version [boolean]
@@ -51,6 +58,7 @@ Examples:
5158
deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json
5259
deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json --port 3001
5360
deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json --delay 500
61+
deno run --allow-read --allow-write --allow-net --allow-run mod.ts db.json --enable-api-prefix
5462
`);
5563
}
5664

@@ -71,6 +79,7 @@ if (import.meta.main) {
7179
q: 'quiet',
7280
nc: 'no-cors',
7381
ro: 'read-only',
82+
api: 'enable-api-prefix',
7483
},
7584
});
7685

@@ -129,6 +138,7 @@ if (import.meta.main) {
129138
delay: args.delay || 0,
130139
quiet: args.quiet || false,
131140
readOnly: args['read-only'] || false,
141+
enableApiPrefix: args['enable-api-prefix'] || false,
132142
};
133143

134144
try {

src/bin/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
* It parses command line arguments and starts a server instance
88
* with the specified configuration.
99
*
10+
* The CLI supports several features including:
11+
* - Database loading from local or remote files
12+
* - Custom routes and middleware
13+
* - API prefix support (/api/* routes)
14+
* - Delay simulation for network latency testing
15+
* - Read-only mode for safe demonstrations
16+
*
1017
* @author webmasterdevlin
1118
* @copyright MIT License
1219
*/
@@ -44,6 +51,7 @@ function parseArgs(): CliArgs {
4451
ro: 'read-only',
4552
nc: 'no-cors',
4653
ng: 'no-gzip',
54+
api: 'enable-api-prefix', // Short alias for enabling API prefix
4755
};
4856

4957
// Parse command line arguments with minimist
@@ -106,6 +114,7 @@ Options:
106114
--read-only, --ro Allow only GET requests [default: false]
107115
--no-cors, --nc Disable CORS [default: false]
108116
--no-gzip, --ng Disable GZIP compression [default: false]
117+
--enable-api-prefix, --api Enable /api/* prefix [default: false]
109118
--delay, -d Add delay to responses (ms) [number]
110119
--id, -i Set database id field [default: "id"]
111120
--foreignKeySuffix Set foreign key suffix [default: "_id"]
@@ -121,6 +130,7 @@ Examples:
121130
json-server db.json --routes routes.js
122131
json-server db.json --delay 1000
123132
json-server db.json --id _id
133+
json-server db.json --enable-api-prefix # Enable /api/* routes
124134
json-server http://example.com/db.json
125135
126136
For more information, visit:
@@ -177,6 +187,7 @@ async function main(): Promise<void> {
177187
delay: cliArgs.delay || 0,
178188
quiet: cliArgs.quiet || false,
179189
readOnly: cliArgs['read-only'] || false,
190+
enableApiPrefix: cliArgs['enable-api-prefix'] || false, // Enable API prefix feature if specified
180191
};
181192

182193
// Create and configure the server

src/index.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
* It provides factory functions, classes, types, and utilities
66
* for creating and managing JSON API servers.
77
*
8+
* The package includes features such as:
9+
* - RESTful API with TypeScript support
10+
* - Custom route configuration
11+
* - API prefix support (/api/* for all routes)
12+
* - CORS, read-only mode, and delay simulation
13+
*
814
* @author webmasterdevlin
915
* @copyright MIT License
1016
*/
@@ -19,7 +25,13 @@ import {
1925
HttpMethod,
2026
RouteHandler,
2127
} from './types';
22-
import { delayMiddleware, corsMiddleware, readOnlyMiddleware, CorsConfig } from './middleware';
28+
import {
29+
delayMiddleware,
30+
corsMiddleware,
31+
readOnlyMiddleware,
32+
apiPrefixMiddleware,
33+
CorsConfig,
34+
} from './middleware';
2335
import * as utils from './utils/utils';
2436

2537
/**
@@ -34,7 +46,8 @@ import * as utils from './utils/utils';
3446
* const server = create({
3547
* port: 3001,
3648
* delay: 500,
37-
* readOnly: true
49+
* readOnly: true,
50+
* enableApiPrefix: true // Enable /api/* prefix for all routes
3851
* });
3952
*
4053
* // Load database and start server
@@ -58,6 +71,7 @@ export function create(options: Partial<ServerOptions> = {}): JsonServer {
5871
delay: options.delay || 0,
5972
quiet: options.quiet || false,
6073
readOnly: options.readOnly || false,
74+
enableApiPrefix: options.enableApiPrefix || false,
6175
};
6276

6377
return createServer(serverOptions);
@@ -82,6 +96,7 @@ export {
8296
delayMiddleware,
8397
corsMiddleware,
8498
readOnlyMiddleware,
99+
apiPrefixMiddleware,
85100
CorsConfig,
86101

87102
// Utilities

src/lib/server.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import bodyParser from 'body-parser';
55
import morgan from 'morgan';
66
import serveStatic from 'serve-static';
77
import { ServerOptions, Database, RoutesConfig, HttpMethod } from '../types';
8-
import { corsMiddleware, delayMiddleware, readOnlyMiddleware } from '../middleware';
8+
import {
9+
corsMiddleware,
10+
delayMiddleware,
11+
readOnlyMiddleware,
12+
apiPrefixMiddleware,
13+
} from '../middleware';
914
import { fileExists, loadJsonFile, saveJsonFile, parseRoutesFile } from '../utils/utils';
1015

1116
/**
@@ -68,6 +73,15 @@ export class JsonServer {
6873
this.app.use(bodyParser.urlencoded({ extended: false, limit: '10mb' }));
6974
}
7075

76+
// API Prefix middleware - allows accessing routes with /api/* prefix
77+
// This enables both standard routes (/users) and prefixed routes (/api/users)
78+
if (this.options.enableApiPrefix) {
79+
this.app.use(apiPrefixMiddleware(this.options.enableApiPrefix));
80+
if (!this.options.quiet) {
81+
console.log('API prefix middleware enabled. Routes can be accessed with /api/* prefix.');
82+
}
83+
}
84+
7185
// Delay middleware for simulating network latency
7286
if (this.options.delay > 0) {
7387
this.app.use(delayMiddleware(this.options.delay));

src/middleware/apiPrefix.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Request, Response, NextFunction, RequestHandler } from 'express';
2+
3+
/**
4+
* Creates middleware to handle API prefix routing
5+
*
6+
* This middleware allows requests to be made with an /api prefix,
7+
* automatically stripping the prefix before processing the request.
8+
* For example, a request to /api/users will be treated as /users internally.
9+
*
10+
* This feature is useful when:
11+
* - You want to make your mock API feel more like a real backend
12+
* - You need to differentiate API routes from other routes in your application
13+
* - You're working with frontend frameworks that expect API routes to start with /api
14+
*
15+
* Both standard routes (/users) and API-prefixed routes (/api/users) will work
16+
* simultaneously when this middleware is enabled.
17+
*
18+
* @param enableApiPrefix - Whether to enable API prefix routing (default: true)
19+
* @returns Express middleware function
20+
*
21+
* @example
22+
* // Usage in Express application
23+
* app.use(apiPrefixMiddleware(true));
24+
*
25+
* // This will allow both these requests to work:
26+
* // GET /users
27+
* // GET /api/users
28+
*/
29+
export function apiPrefixMiddleware(enableApiPrefix: boolean = true): RequestHandler {
30+
// If API prefix is disabled, return a pass-through middleware
31+
if (!enableApiPrefix) {
32+
return (_req: Request, _res: Response, next: NextFunction): void => {
33+
next();
34+
};
35+
}
36+
37+
return (req: Request, _res: Response, next: NextFunction): void => {
38+
// Check if the request path starts with /api/
39+
if (req.path.startsWith('/api/')) {
40+
// Rewrite the URL by removing the /api prefix
41+
req.url = req.url.replace(/^\/api/, '');
42+
}
43+
44+
next();
45+
};
46+
}

src/middleware/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
*
44
* This file exports all middleware components for the json-server package.
55
* These middlewares handle common HTTP server functionality such as CORS,
6-
* response delays, and read-only mode.
6+
* response delays, read-only mode, and API prefix routing.
77
*/
88

99
import { corsMiddleware, CorsConfig } from './cors';
1010
import { delayMiddleware } from './delay';
1111
import { readOnlyMiddleware } from './readOnly';
12+
import { apiPrefixMiddleware } from './apiPrefix';
1213

13-
export { corsMiddleware, delayMiddleware, readOnlyMiddleware, CorsConfig };
14+
export { corsMiddleware, delayMiddleware, readOnlyMiddleware, apiPrefixMiddleware, CorsConfig };

src/types/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ export interface ServerOptions {
3737

3838
/** Whether to make the server read-only (no POST, PUT, PATCH, DELETE) */
3939
readOnly: boolean;
40+
41+
/**
42+
* Whether to enable API prefix (/api/*) for all routes
43+
* When enabled, all routes can be accessed both directly (/users)
44+
* and with an /api prefix (/api/users)
45+
*/
46+
enableApiPrefix: boolean;
4047
}
4148

4249
/**
@@ -92,6 +99,12 @@ export interface CliArgs {
9299
/** Path to file for database snapshots */
93100
snapshot?: string;
94101

102+
/**
103+
* Whether to enable API prefix feature
104+
* When enabled, all routes can be accessed with /api/* prefix
105+
*/
106+
'enable-api-prefix'?: boolean;
107+
95108
/** Additional, unknown command line arguments */
96109
[key: string]: any;
97110
}

0 commit comments

Comments
 (0)