@vnphu/nestjs-api-explorer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -0
- package/dist/api-explorer.controller.d.ts +16 -0
- package/dist/api-explorer.controller.d.ts.map +1 -0
- package/dist/api-explorer.controller.js +61 -0
- package/dist/api-explorer.controller.js.map +1 -0
- package/dist/api-explorer.html.d.ts +3 -0
- package/dist/api-explorer.html.d.ts.map +1 -0
- package/dist/api-explorer.html.js +1066 -0
- package/dist/api-explorer.html.js.map +1 -0
- package/dist/api-explorer.module.d.ts +15 -0
- package/dist/api-explorer.module.d.ts.map +1 -0
- package/dist/api-explorer.module.js +46 -0
- package/dist/api-explorer.module.js.map +1 -0
- package/dist/api-explorer.service.d.ts +14 -0
- package/dist/api-explorer.service.d.ts.map +1 -0
- package/dist/api-explorer.service.js +92 -0
- package/dist/api-explorer.service.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# nestjs-api-docs
|
|
2
|
+
|
|
3
|
+
An in-app API explorer for NestJS — like Postman, but embedded directly into your application. Zero external dependencies, dark-themed, and auto-disabled in production.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Route auto-discovery** — scans the live Express router, no decorators needed
|
|
8
|
+
- **Full request builder** — path params, query params, headers, auth, and body
|
|
9
|
+
- **Auth support** — Bearer Token, Basic Auth, API Key (header or query)
|
|
10
|
+
- **Body types** — JSON (with formatter), Form-encoded, Plain text
|
|
11
|
+
- **Response viewer** — syntax-highlighted JSON, status badge, timing, response headers
|
|
12
|
+
- **Resizable panels** — drag-to-resize sidebar and request/response split
|
|
13
|
+
- **Auto-disabled in production** — safe to leave in your codebase
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install nestjs-api-docs
|
|
19
|
+
# or
|
|
20
|
+
yarn add nestjs-api-docs
|
|
21
|
+
# or
|
|
22
|
+
pnpm add nestjs-api-docs
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Register the module in your `AppModule`:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Module } from '@nestjs/common';
|
|
31
|
+
import { ApiExplorerModule } from 'nestjs-api-docs';
|
|
32
|
+
|
|
33
|
+
@Module({
|
|
34
|
+
imports: [
|
|
35
|
+
ApiExplorerModule.register({
|
|
36
|
+
path: 'api-explorer', // UI available at GET /api-explorer
|
|
37
|
+
title: 'My API',
|
|
38
|
+
enabled: true, // auto-false in production
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
})
|
|
42
|
+
export class AppModule {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then start your app and visit:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
http://localhost:3000/api-explorer
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Options
|
|
52
|
+
|
|
53
|
+
| Option | Type | Default | Description |
|
|
54
|
+
|-----------|-----------|------------------|-----------------------------------------------------------------|
|
|
55
|
+
| `path` | `string` | `'api-explorer'` | URL path prefix where the explorer is served |
|
|
56
|
+
| `title` | `string` | `'API Explorer'` | Title shown in the browser tab and UI header |
|
|
57
|
+
| `enabled` | `boolean` | `true` | Explicitly enable/disable. Always disabled when `NODE_ENV=production` |
|
|
58
|
+
|
|
59
|
+
## Endpoints
|
|
60
|
+
|
|
61
|
+
Once registered, two endpoints are added:
|
|
62
|
+
|
|
63
|
+
| Method | Path | Description |
|
|
64
|
+
|--------|------------------------|--------------------------------------|
|
|
65
|
+
| `GET` | `/{path}` | Serves the explorer HTML UI |
|
|
66
|
+
| `GET` | `/{path}/routes` | Returns discovered routes as JSON |
|
|
67
|
+
|
|
68
|
+
### Route response format
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"method": "GET",
|
|
74
|
+
"path": "/users",
|
|
75
|
+
"params": []
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"method": "GET",
|
|
79
|
+
"path": "/users/:id",
|
|
80
|
+
"params": ["id"]
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Using the UI
|
|
86
|
+
|
|
87
|
+
1. **Select a route** from the sidebar (use the search bar to filter)
|
|
88
|
+
2. **Fill in parameters** — path params are auto-detected and shown first
|
|
89
|
+
3. **Set headers / auth / body** using the tabs in the request panel
|
|
90
|
+
4. **Click Send** (or press `Ctrl+Enter` / `Cmd+Enter`)
|
|
91
|
+
5. **Inspect the response** — body with JSON highlighting, status, timing, and headers
|
|
92
|
+
|
|
93
|
+
### Auth tab
|
|
94
|
+
|
|
95
|
+
| Type | Description |
|
|
96
|
+
|---------------|----------------------------------------------------------|
|
|
97
|
+
| None | No Authorization header |
|
|
98
|
+
| Bearer Token | Adds `Authorization: Bearer <token>` |
|
|
99
|
+
| Basic Auth | Adds `Authorization: Basic <base64(user:pass)>` |
|
|
100
|
+
| API Key | Adds a custom key to a header or as a query parameter |
|
|
101
|
+
|
|
102
|
+
### Body tab
|
|
103
|
+
|
|
104
|
+
| Type | Content-Type |
|
|
105
|
+
|--------|-------------------------------------|
|
|
106
|
+
| None | No body sent |
|
|
107
|
+
| JSON | `application/json` + Format button |
|
|
108
|
+
| Form | `application/x-www-form-urlencoded` |
|
|
109
|
+
| Text | `text/plain` |
|
|
110
|
+
|
|
111
|
+
## Peer dependencies
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"@nestjs/common": ">=9.0.0",
|
|
116
|
+
"@nestjs/core": ">=9.0.0"
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## How it works
|
|
121
|
+
|
|
122
|
+
`ApiExplorerService` uses NestJS's `HttpAdapterHost` to access the underlying Express app instance and traverses `app._router.stack` to discover all registered routes at request time. This means the route list is always up-to-date with whatever is actually mounted on the Express router.
|
|
123
|
+
|
|
124
|
+
## Production safety
|
|
125
|
+
|
|
126
|
+
The module automatically returns an empty `DynamicModule` (no controllers, no providers) when `NODE_ENV === 'production'`, so there is no runtime overhead and no routes are exposed.
|
|
127
|
+
|
|
128
|
+
You can also disable it explicitly:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
ApiExplorerModule.register({ enabled: false })
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ResolvedApiExplorerOptions } from './api-explorer.module';
|
|
2
|
+
import { ApiExplorerService } from './api-explorer.service';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an ApiExplorer controller bound to the given path at runtime.
|
|
5
|
+
* Using a factory lets us set @Controller(path) dynamically from options
|
|
6
|
+
* without requiring decorators at compile time.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createApiExplorerController(explorerPath: string): {
|
|
9
|
+
new (service: ApiExplorerService, options: ResolvedApiExplorerOptions): {
|
|
10
|
+
readonly service: ApiExplorerService;
|
|
11
|
+
readonly options: ResolvedApiExplorerOptions;
|
|
12
|
+
getUi(res: any): void;
|
|
13
|
+
getRoutes(req: any): import("./api-explorer.service").RouteInfo[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=api-explorer.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-explorer.controller.d.ts","sourceRoot":"","sources":["../src/api-explorer.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM;kBAIjC,kBAAkB,WAElB,0BAA0B;0BAF1B,kBAAkB;0BAElB,0BAA0B;mBAInC,GAAG,GAAG,IAAI;uBAON,GAAG;;EAM5B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createApiExplorerController = createApiExplorerController;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const api_explorer_module_1 = require("./api-explorer.module");
|
|
18
|
+
const api_explorer_service_1 = require("./api-explorer.service");
|
|
19
|
+
const api_explorer_html_1 = require("./api-explorer.html");
|
|
20
|
+
/**
|
|
21
|
+
* Creates an ApiExplorer controller bound to the given path at runtime.
|
|
22
|
+
* Using a factory lets us set @Controller(path) dynamically from options
|
|
23
|
+
* without requiring decorators at compile time.
|
|
24
|
+
*/
|
|
25
|
+
function createApiExplorerController(explorerPath) {
|
|
26
|
+
let ApiExplorerController = class ApiExplorerController {
|
|
27
|
+
constructor(service, options) {
|
|
28
|
+
this.service = service;
|
|
29
|
+
this.options = options;
|
|
30
|
+
}
|
|
31
|
+
getUi(res) {
|
|
32
|
+
const html = (0, api_explorer_html_1.getExplorerHtml)(this.options);
|
|
33
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
34
|
+
res.send(html);
|
|
35
|
+
}
|
|
36
|
+
getRoutes(req) {
|
|
37
|
+
return this.service.getRoutes(req.app);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, common_1.Get)(),
|
|
42
|
+
__param(0, (0, common_1.Res)()),
|
|
43
|
+
__metadata("design:type", Function),
|
|
44
|
+
__metadata("design:paramtypes", [Object]),
|
|
45
|
+
__metadata("design:returntype", void 0)
|
|
46
|
+
], ApiExplorerController.prototype, "getUi", null);
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, common_1.Get)('routes'),
|
|
49
|
+
__param(0, (0, common_1.Req)()),
|
|
50
|
+
__metadata("design:type", Function),
|
|
51
|
+
__metadata("design:paramtypes", [Object]),
|
|
52
|
+
__metadata("design:returntype", void 0)
|
|
53
|
+
], ApiExplorerController.prototype, "getRoutes", null);
|
|
54
|
+
ApiExplorerController = __decorate([
|
|
55
|
+
(0, common_1.Controller)(explorerPath),
|
|
56
|
+
__param(1, (0, common_1.Inject)(api_explorer_module_1.API_EXPLORER_OPTIONS)),
|
|
57
|
+
__metadata("design:paramtypes", [api_explorer_service_1.ApiExplorerService, Object])
|
|
58
|
+
], ApiExplorerController);
|
|
59
|
+
return ApiExplorerController;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=api-explorer.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-explorer.controller.js","sourceRoot":"","sources":["../src/api-explorer.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAUA,kEAuBC;AAjCD,2CAAmE;AACnE,+DAAyF;AACzF,iEAA4D;AAC5D,2DAAsD;AAEtD;;;;GAIG;AACH,SAAgB,2BAA2B,CAAC,YAAoB;IAC9D,IACM,qBAAqB,GAD3B,MACM,qBAAqB;QACzB,YACkB,OAA2B,EAE3B,OAAmC;YAFnC,YAAO,GAAP,OAAO,CAAoB;YAE3B,YAAO,GAAP,OAAO,CAA4B;QAClD,CAAC;QAGJ,KAAK,CAAQ,GAAQ;YACnB,MAAM,IAAI,GAAG,IAAA,mCAAe,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3C,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;QAGD,SAAS,CAAQ,GAAQ;YACvB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;KACF,CAAA;IAVC;QADC,IAAA,YAAG,GAAE;QACC,WAAA,IAAA,YAAG,GAAE,CAAA;;;;sDAIX;IAGD;QADC,IAAA,YAAG,EAAC,QAAQ,CAAC;QACH,WAAA,IAAA,YAAG,GAAE,CAAA;;;;0DAEf;IAjBG,qBAAqB;QAD1B,IAAA,mBAAU,EAAC,YAAY,CAAC;QAIpB,WAAA,IAAA,eAAM,EAAC,0CAAoB,CAAC,CAAA;yCADJ,yCAAkB;OAFzC,qBAAqB,CAkB1B;IAED,OAAO,qBAAqB,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-explorer.html.d.ts","sourceRoot":"","sources":["../src/api-explorer.html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAsiC3E"}
|