@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 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,3 @@
1
+ import { ResolvedApiExplorerOptions } from './api-explorer.module';
2
+ export declare function getExplorerHtml(options: ResolvedApiExplorerOptions): string;
3
+ //# sourceMappingURL=api-explorer.html.d.ts.map
@@ -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"}