@umeshindu222/apisnap 1.1.3 → 1.1.5
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 +471 -66
- package/dist/core/runner.js +335 -110
- package/dist/core/runner.js.map +1 -1
- package/dist/middleware/index.d.ts +8 -2
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +44 -22
- package/dist/middleware/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,60 +7,315 @@
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## What is APISnap?
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Every time you change your Express backend, manually testing all your routes in Postman is slow and boring. **APISnap auto-discovers every route in your app and health-checks all of them in seconds** — with zero configuration.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
One command. Every route. Instant results.
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Features
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
20
|
+
- 🔍 **Auto Route Discovery** — finds every route including nested sub-routers
|
|
21
|
+
- 🔐 **Full Auth Support** — JWT, API Keys, Cookies, multiple headers at once
|
|
22
|
+
- 💡 **Auth Hints** — tells you exactly how to fix 401/403 errors
|
|
23
|
+
- ⚡ **Slow Route Detection** — flags endpoints that are too slow
|
|
24
|
+
- 🔁 **Retry Logic** — auto-retries failed requests
|
|
25
|
+
- 📊 **HTML Reports** — beautiful visual reports you can share
|
|
26
|
+
- 💾 **JSON Export** — structured output for CI/CD pipelines
|
|
27
|
+
- ⚙️ **Config File** — save your settings so you don't retype every time
|
|
28
|
+
- 🎯 **Method Filter** — test only GET, POST, DELETE etc.
|
|
29
|
+
- 🧠 **Smart Path Params** — auto-replaces `:id`, `:slug`, `:uuid` with safe defaults
|
|
30
|
+
- 🚀 **Express v4 & v5** — works with both versions
|
|
26
31
|
|
|
27
32
|
---
|
|
28
33
|
|
|
29
|
-
##
|
|
34
|
+
## Quick Start
|
|
30
35
|
|
|
31
|
-
### Step 1
|
|
36
|
+
### Step 1 — Install
|
|
32
37
|
|
|
33
38
|
```bash
|
|
34
39
|
npm install @umeshindu222/apisnap
|
|
35
40
|
```
|
|
36
41
|
|
|
42
|
+
### Step 2 — Add to your server file
|
|
43
|
+
|
|
44
|
+
Open your main server file (`server.js`, `app.js`, `app.ts`) and add **2 lines**:
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
const apisnap = require('@umeshindu222/apisnap'); // ADD THIS at the top
|
|
48
|
+
|
|
49
|
+
// ... all your existing routes stay exactly the same ...
|
|
50
|
+
|
|
51
|
+
apisnap.init(app); // ADD THIS — after your routes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Step 3 — Start your server
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
node server.js
|
|
58
|
+
# or
|
|
59
|
+
npm run dev
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
You will see this line confirming it works:
|
|
63
|
+
```
|
|
64
|
+
✅ [APISnap] Discovery active → http://localhost:3000/__apisnap_discovery
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Step 4 — Run the health check
|
|
68
|
+
|
|
69
|
+
Open a **second terminal** in your project folder and run:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx @umeshindu222/apisnap --port 3000
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
That's it. You will see every route tested automatically.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Full Setup Examples
|
|
80
|
+
|
|
81
|
+
### JavaScript (CommonJS)
|
|
82
|
+
|
|
37
83
|
```javascript
|
|
38
84
|
const express = require('express');
|
|
39
85
|
const apisnap = require('@umeshindu222/apisnap');
|
|
40
86
|
|
|
41
87
|
const app = express();
|
|
88
|
+
app.use(express.json());
|
|
42
89
|
|
|
43
|
-
// Your routes
|
|
90
|
+
// Your routes
|
|
91
|
+
app.get('/health', (req, res) => res.json({ status: 'ok' }));
|
|
44
92
|
app.get('/users', (req, res) => res.json({ users: [] }));
|
|
45
|
-
app.post('/users', (req, res) => res.json({ message: '
|
|
93
|
+
app.post('/users', (req, res) => res.json({ message: 'created' }));
|
|
94
|
+
app.delete('/users/:id', (req, res) => res.json({ deleted: true }));
|
|
46
95
|
|
|
47
|
-
//
|
|
96
|
+
// APISnap — place AFTER your routes
|
|
97
|
+
apisnap.init(app);
|
|
98
|
+
|
|
99
|
+
app.listen(3000, () => console.log('Server running on port 3000'));
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### TypeScript
|
|
105
|
+
|
|
106
|
+
> ⚠️ **TypeScript users — import must be written exactly like this:**
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// ✅ CORRECT — use import * as
|
|
110
|
+
import * as apisnap from '@umeshindu222/apisnap';
|
|
111
|
+
|
|
112
|
+
// ❌ WRONG — will give "has no default export" red error
|
|
113
|
+
import apisnap from '@umeshindu222/apisnap';
|
|
114
|
+
|
|
115
|
+
// ❌ WRONG — never mix import and require in TypeScript
|
|
116
|
+
import apisnap from '@umeshindu222/apisnap';
|
|
117
|
+
const apisnap = require('@umeshindu222/apisnap');
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Full example:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import express, { Application, Request, Response, NextFunction } from 'express';
|
|
124
|
+
import * as apisnap from '@umeshindu222/apisnap'; // ✅ correct
|
|
125
|
+
|
|
126
|
+
const app: Application = express();
|
|
127
|
+
app.use(express.json());
|
|
128
|
+
|
|
129
|
+
// Your routes
|
|
130
|
+
app.get('/health', (req: Request, res: Response) => res.json({ status: 'ok' }));
|
|
131
|
+
app.get('/users', (req: Request, res: Response) => res.json({ users: [] }));
|
|
132
|
+
app.post('/users', (req: Request, res: Response) => res.json({ message: 'created' }));
|
|
133
|
+
|
|
134
|
+
// APISnap — place AFTER your routes
|
|
135
|
+
apisnap.init(app);
|
|
136
|
+
|
|
137
|
+
app.listen(3000, () => console.log('Server running on port 3000'));
|
|
138
|
+
|
|
139
|
+
export default app;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
If TypeScript still shows a red error under the import, create a file called `apisnap.d.ts` in your project root:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
declare module '@umeshindu222/apisnap' {
|
|
146
|
+
interface APISnapOptions {
|
|
147
|
+
skip?: string[];
|
|
148
|
+
name?: string;
|
|
149
|
+
}
|
|
150
|
+
export function init(app: any, options?: APISnapOptions): void;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### With Sub-Routers (Real World Project)
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const express = require('express');
|
|
160
|
+
const apisnap = require('@umeshindu222/apisnap');
|
|
161
|
+
const userRoutes = require('./routes/users');
|
|
162
|
+
const postRoutes = require('./routes/posts');
|
|
163
|
+
const authRoutes = require('./routes/auth');
|
|
164
|
+
|
|
165
|
+
const app = express();
|
|
166
|
+
app.use(express.json());
|
|
167
|
+
|
|
168
|
+
// Register all your routers
|
|
169
|
+
app.use('/api/users', userRoutes);
|
|
170
|
+
app.use('/api/posts', postRoutes);
|
|
171
|
+
app.use('/api/auth', authRoutes);
|
|
172
|
+
|
|
173
|
+
// APISnap discovers ALL routes including sub-routers
|
|
48
174
|
apisnap.init(app);
|
|
49
175
|
|
|
50
176
|
app.listen(3000);
|
|
51
177
|
```
|
|
52
178
|
|
|
53
|
-
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### With Global Auth Middleware
|
|
182
|
+
|
|
183
|
+
> ⚠️ **Important:** If you use global auth middleware (`app.use(authMiddleware)`), you must place `apisnap.init(app)` **before** it. Otherwise auth will block the discovery endpoint.
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
const express = require('express');
|
|
187
|
+
const apisnap = require('@umeshindu222/apisnap');
|
|
188
|
+
const authMiddleware = require('./middleware/auth');
|
|
189
|
+
|
|
190
|
+
const app = express();
|
|
191
|
+
app.use(express.json());
|
|
192
|
+
|
|
193
|
+
// Register routes first
|
|
194
|
+
app.get('/health', (req, res) => res.json({ status: 'ok' }));
|
|
195
|
+
app.use('/api/users', userRoutes);
|
|
196
|
+
app.use('/api/posts', postRoutes);
|
|
197
|
+
|
|
198
|
+
// ✅ APISnap BEFORE global auth middleware
|
|
199
|
+
apisnap.init(app);
|
|
200
|
+
|
|
201
|
+
// ✅ Global auth AFTER apisnap
|
|
202
|
+
app.use(authMiddleware);
|
|
203
|
+
|
|
204
|
+
app.listen(3000);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Skip Specific Routes
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
// Don't test certain routes (e.g. auth callbacks, webhooks, admin)
|
|
213
|
+
apisnap.init(app, {
|
|
214
|
+
skip: ['/api/auth', '/webhooks', '/admin']
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 🔐 Fixing 401 / 403 Errors
|
|
221
|
+
|
|
222
|
+
401 and 403 errors are **completely normal** — it just means your routes are protected and APISnap needs credentials, exactly like any real client would.
|
|
223
|
+
|
|
224
|
+
### JWT / Bearer Token
|
|
54
225
|
|
|
55
226
|
```bash
|
|
56
|
-
npx @umeshindu222/apisnap --port 3000
|
|
227
|
+
npx @umeshindu222/apisnap --port 3000 -H "Authorization: Bearer eyJhbGci..."
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### API Key
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
npx @umeshindu222/apisnap --port 3000 -H "x-api-key: your-secret-key"
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Cookie / Session Auth (Passport.js, express-session)
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
npx @umeshindu222/apisnap --port 3000 --cookie "connect.sid=s%3Aabc123"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Multiple Headers at Once
|
|
243
|
+
|
|
244
|
+
The `-H` flag can be repeated as many times as you need:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
npx @umeshindu222/apisnap --port 3000 \
|
|
248
|
+
-H "Authorization: Bearer TOKEN" \
|
|
249
|
+
-H "x-api-key: SECRET" \
|
|
250
|
+
-H "x-tenant-id: my-company"
|
|
57
251
|
```
|
|
58
252
|
|
|
59
|
-
|
|
253
|
+
### How to Get Your JWT Token
|
|
254
|
+
|
|
255
|
+
1. Open Postman
|
|
256
|
+
2. Call your login endpoint:
|
|
257
|
+
```
|
|
258
|
+
POST http://localhost:3000/api/auth/login
|
|
259
|
+
Content-Type: application/json
|
|
260
|
+
|
|
261
|
+
{
|
|
262
|
+
"email": "your@email.com",
|
|
263
|
+
"password": "yourpassword"
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
3. Copy the token from the response
|
|
267
|
+
4. Use it in the `-H` flag above
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## ⚙️ Config File (Recommended)
|
|
272
|
+
|
|
273
|
+
Instead of typing your token every single time, save your settings in a config file. Create `.apisnaprc.json` in your project root:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"port": "3000",
|
|
278
|
+
"slow": "300",
|
|
279
|
+
"headers": [
|
|
280
|
+
"Authorization: Bearer YOUR_JWT_TOKEN_HERE"
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Now just run with no flags:
|
|
286
|
+
```bash
|
|
287
|
+
npx @umeshindu222/apisnap
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
APISnap reads the config file automatically.
|
|
291
|
+
|
|
292
|
+
> ⚠️ **Add `.apisnaprc.json` to your `.gitignore`** so your token is never committed to GitHub.
|
|
293
|
+
|
|
294
|
+
### Full Config File Options
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"port": "3000",
|
|
299
|
+
"slow": "300",
|
|
300
|
+
"timeout": "5000",
|
|
301
|
+
"retry": "1",
|
|
302
|
+
"headers": [
|
|
303
|
+
"Authorization: Bearer YOUR_TOKEN",
|
|
304
|
+
"x-api-key: YOUR_API_KEY"
|
|
305
|
+
],
|
|
306
|
+
"cookie": "sessionId=your-session-id",
|
|
307
|
+
"params": {
|
|
308
|
+
"id": "1",
|
|
309
|
+
"userId": "1",
|
|
310
|
+
"slug": "hello-world",
|
|
311
|
+
"uuid": "550e8400-e29b-41d4-a716-446655440000"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
```
|
|
60
315
|
|
|
61
316
|
---
|
|
62
317
|
|
|
63
|
-
##
|
|
318
|
+
## CLI Reference
|
|
64
319
|
|
|
65
320
|
```bash
|
|
66
321
|
npx @umeshindu222/apisnap [options]
|
|
@@ -68,114 +323,264 @@ npx @umeshindu222/apisnap [options]
|
|
|
68
323
|
|
|
69
324
|
| Option | Description | Default |
|
|
70
325
|
|--------|-------------|---------|
|
|
71
|
-
| `-p, --port <
|
|
72
|
-
| `-H, --header <
|
|
73
|
-
| `-
|
|
74
|
-
| `-
|
|
75
|
-
| `-
|
|
76
|
-
| `-
|
|
326
|
+
| `-p, --port <n>` | Port your server runs on | `3000` |
|
|
327
|
+
| `-H, --header <str>` | Auth header — can repeat multiple times | — |
|
|
328
|
+
| `-c, --cookie <str>` | Cookie string for session auth | — |
|
|
329
|
+
| `-s, --slow <n>` | Flag routes slower than this (ms) | `200` |
|
|
330
|
+
| `-t, --timeout <n>` | Request timeout in ms | `5000` |
|
|
331
|
+
| `-r, --retry <n>` | Retry failed requests N times | `0` |
|
|
332
|
+
| `-e, --export <file>` | Save JSON report to file | — |
|
|
333
|
+
| `--html <file>` | Save HTML report to file | — |
|
|
334
|
+
| `--only <methods>` | Only test these methods e.g. `GET,POST` | — |
|
|
335
|
+
| `--base-url <url>` | Test a different server e.g. staging | `localhost` |
|
|
336
|
+
| `--params <json>` | Override path params as JSON | — |
|
|
337
|
+
| `--fail-on-slow` | Exit code 1 if slow routes found | `false` |
|
|
77
338
|
|
|
78
339
|
---
|
|
79
340
|
|
|
80
|
-
##
|
|
341
|
+
## Examples
|
|
81
342
|
|
|
82
|
-
### Basic
|
|
343
|
+
### Basic check
|
|
83
344
|
```bash
|
|
84
345
|
npx @umeshindu222/apisnap --port 3000
|
|
85
346
|
```
|
|
86
347
|
|
|
87
|
-
### With
|
|
348
|
+
### With JWT auth
|
|
88
349
|
```bash
|
|
89
|
-
npx @umeshindu222/apisnap
|
|
350
|
+
npx @umeshindu222/apisnap -p 3000 -H "Authorization: Bearer eyJhbGci..."
|
|
90
351
|
```
|
|
91
352
|
|
|
92
|
-
### Custom
|
|
353
|
+
### Custom path params
|
|
354
|
+
|
|
355
|
+
If your route is `/users/:id/posts/:postId` and the default `1` doesn't work in your database:
|
|
93
356
|
```bash
|
|
94
|
-
npx @umeshindu222/apisnap --
|
|
357
|
+
npx @umeshindu222/apisnap --params '{"id":"42","postId":"7"}'
|
|
95
358
|
```
|
|
96
359
|
|
|
97
|
-
###
|
|
360
|
+
### Only test GET routes
|
|
98
361
|
```bash
|
|
99
|
-
npx @umeshindu222/apisnap --
|
|
100
|
-
# Creates: my-report.json
|
|
362
|
+
npx @umeshindu222/apisnap --only GET
|
|
101
363
|
```
|
|
102
364
|
|
|
103
|
-
###
|
|
365
|
+
### Test your staging server
|
|
104
366
|
```bash
|
|
105
|
-
npx @umeshindu222/apisnap --
|
|
367
|
+
npx @umeshindu222/apisnap --base-url https://staging.myapp.com -H "Authorization: Bearer TOKEN"
|
|
106
368
|
```
|
|
107
369
|
|
|
108
|
-
|
|
370
|
+
### Generate an HTML report
|
|
371
|
+
```bash
|
|
372
|
+
npx @umeshindu222/apisnap --html report
|
|
373
|
+
```
|
|
109
374
|
|
|
110
|
-
|
|
375
|
+
Then open it:
|
|
376
|
+
```bash
|
|
377
|
+
# Windows
|
|
378
|
+
start report.html
|
|
379
|
+
|
|
380
|
+
# Mac
|
|
381
|
+
open report.html
|
|
111
382
|
|
|
383
|
+
# Linux
|
|
384
|
+
xdg-open report.html
|
|
112
385
|
```
|
|
113
|
-
📸 APISnap v1.0.0
|
|
114
|
-
Slow threshold: 200ms
|
|
115
386
|
|
|
116
|
-
|
|
387
|
+
### Generate a JSON report
|
|
388
|
+
```bash
|
|
389
|
+
npx @umeshindu222/apisnap --export report
|
|
390
|
+
# Creates: report.json
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Retry flaky endpoints
|
|
394
|
+
```bash
|
|
395
|
+
npx @umeshindu222/apisnap --retry 3
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### CI/CD — fail the pipeline if any endpoint is broken
|
|
399
|
+
```bash
|
|
400
|
+
npx @umeshindu222/apisnap --export ci-report
|
|
401
|
+
# Exits with code 1 automatically if any endpoint fails
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### All options together
|
|
405
|
+
```bash
|
|
406
|
+
npx @umeshindu222/apisnap \
|
|
407
|
+
-p 5000 \
|
|
408
|
+
-H "Authorization: Bearer TOKEN" \
|
|
409
|
+
-H "x-api-key: SECRET" \
|
|
410
|
+
--cookie "sessionId=abc" \
|
|
411
|
+
--slow 300 \
|
|
412
|
+
--retry 2 \
|
|
413
|
+
--html report \
|
|
414
|
+
--export report
|
|
415
|
+
```
|
|
117
416
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Sample Output
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
📸 APISnap v1.1.4
|
|
423
|
+
Target: http://localhost:3000
|
|
424
|
+
Slow: >200ms
|
|
425
|
+
Timeout: 5000ms
|
|
426
|
+
Headers: {"Authorization":"Bearer ey••••••"}
|
|
427
|
+
|
|
428
|
+
✔ Connected! Found 6 endpoints to test.
|
|
429
|
+
|
|
430
|
+
✔ GET /health [200] 3ms
|
|
431
|
+
✔ GET /users [200] 12ms
|
|
432
|
+
✔ POST /users [200] 8ms
|
|
433
|
+
✔ GET /users/1 [200] 5ms
|
|
434
|
+
⚠️ GET /reports [200] 543ms ← slow!
|
|
435
|
+
✖ DELETE /users/1 [401] 2ms
|
|
436
|
+
💡 Hint: 401 Unauthorized — try adding -H "Authorization: Bearer YOUR_TOKEN"
|
|
124
437
|
|
|
125
438
|
📊 Summary:
|
|
126
439
|
✅ Passed: 5
|
|
127
440
|
❌ Failed: 1
|
|
128
441
|
⚠️ Slow: 1 (>200ms)
|
|
442
|
+
⏱ Avg: 95ms
|
|
443
|
+
🕐 Total: 573ms
|
|
129
444
|
|
|
130
445
|
⚠️ Some endpoints are unhealthy!
|
|
131
446
|
```
|
|
132
447
|
|
|
133
448
|
---
|
|
134
449
|
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
When using `--export`, a structured JSON file is created:
|
|
450
|
+
## JSON Report Format
|
|
138
451
|
|
|
139
452
|
```json
|
|
140
453
|
{
|
|
141
454
|
"tool": "APISnap",
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
455
|
+
"version": "1.1.4",
|
|
456
|
+
"generatedAt": "2026-03-08T10:00:00.000Z",
|
|
457
|
+
"config": {
|
|
458
|
+
"port": "3000",
|
|
459
|
+
"slowThreshold": 200,
|
|
460
|
+
"timeout": 5000
|
|
461
|
+
},
|
|
462
|
+
"summary": {
|
|
463
|
+
"total": 6,
|
|
464
|
+
"passed": 5,
|
|
465
|
+
"failed": 1,
|
|
466
|
+
"slow": 1,
|
|
467
|
+
"avgDuration": 95,
|
|
468
|
+
"totalDuration": 573
|
|
469
|
+
},
|
|
145
470
|
"results": [
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
471
|
+
{
|
|
472
|
+
"method": "GET",
|
|
473
|
+
"path": "/users",
|
|
474
|
+
"status": 200,
|
|
475
|
+
"duration": 12,
|
|
476
|
+
"success": true,
|
|
477
|
+
"slow": false,
|
|
478
|
+
"retries": 0
|
|
479
|
+
}
|
|
149
480
|
]
|
|
150
481
|
}
|
|
151
482
|
```
|
|
152
483
|
|
|
153
|
-
> **CI/CD tip:**
|
|
484
|
+
> **CI/CD tip:** Check `summary.failed > 0` to fail your build automatically.
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## Common Problems & Fixes
|
|
489
|
+
|
|
490
|
+
### "Cannot reach discovery endpoint"
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
✖ Cannot reach discovery endpoint: http://localhost:3000/__apisnap_discovery
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Causes:**
|
|
497
|
+
- Your server is not running — start it first in another terminal
|
|
498
|
+
- Wrong port — use `-p YOUR_PORT` to specify the correct one
|
|
499
|
+
- You forgot to add `apisnap.init(app)` to your server
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
### All routes show 401
|
|
504
|
+
|
|
505
|
+
**Cause:** Your routes are protected and no credentials were provided.
|
|
506
|
+
|
|
507
|
+
**Fix:**
|
|
508
|
+
```bash
|
|
509
|
+
npx @umeshindu222/apisnap -H "Authorization: Bearer YOUR_REAL_TOKEN"
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Also check your middleware order — `apisnap.init(app)` must come **before** any global `app.use(authMiddleware)`.
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
### Routes are missing from the output
|
|
517
|
+
|
|
518
|
+
**Cause:** `apisnap.init(app)` was called before the routes were registered.
|
|
519
|
+
|
|
520
|
+
**Fix:** Make sure `apisnap.init(app)` is the **last thing** before `app.listen()`:
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
// All routes first
|
|
524
|
+
app.use('/api/users', userRoutes);
|
|
525
|
+
app.use('/api/posts', postRoutes);
|
|
526
|
+
|
|
527
|
+
// APISnap last (before app.listen)
|
|
528
|
+
apisnap.init(app);
|
|
529
|
+
|
|
530
|
+
app.listen(3000);
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
### Config file not loading
|
|
536
|
+
|
|
537
|
+
**Cause:** On Windows, creating JSON files with PowerShell `echo` saves them with wrong encoding (UTF-16).
|
|
538
|
+
|
|
539
|
+
**Fix:** Create `.apisnaprc.json` manually in VS Code or Notepad — File → Save As → select **UTF-8** encoding.
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
### 404 on routes with path params
|
|
544
|
+
|
|
545
|
+
Routes like `/users/:id` get `:id` replaced with `1` by default. If `1` is not a valid ID in your database, override it:
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
npx @umeshindu222/apisnap --params '{"id":"YOUR_REAL_ID"}'
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Or in your config file:
|
|
552
|
+
```json
|
|
553
|
+
{
|
|
554
|
+
"params": {
|
|
555
|
+
"id": "64f1a2b3c4d5e6f7a8b9c0d1"
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
```
|
|
154
559
|
|
|
155
560
|
---
|
|
156
561
|
|
|
157
|
-
##
|
|
562
|
+
## How It Works
|
|
158
563
|
|
|
159
|
-
APISnap
|
|
564
|
+
APISnap has two parts:
|
|
160
565
|
|
|
161
|
-
1.
|
|
566
|
+
**1. Middleware** — `apisnap.init(app)` registers a hidden endpoint `/__apisnap_discovery` in your Express app. When called, it recursively walks the entire Express router stack and returns a map of every registered route — including all nested sub-routers.
|
|
162
567
|
|
|
163
|
-
2.
|
|
568
|
+
**2. CLI** — `npx @umeshindu222/apisnap` calls the discovery endpoint, gets the full route list, then sends a real HTTP request to each route using your headers and cookies. It replaces path params with smart defaults (`:id` → `1`, `:uuid` → valid UUID, `:slug` → `"example"`), measures response time, and reports everything.
|
|
164
569
|
|
|
165
570
|
---
|
|
166
571
|
|
|
167
|
-
##
|
|
572
|
+
## Contributing
|
|
168
573
|
|
|
169
574
|
Contributions, issues and feature requests are welcome!
|
|
170
575
|
|
|
171
576
|
1. Fork the repo
|
|
172
|
-
2. Create your
|
|
173
|
-
3. Commit
|
|
174
|
-
4. Push
|
|
577
|
+
2. Create your branch: `git checkout -b feat/amazing-feature`
|
|
578
|
+
3. Commit: `git commit -m 'feat: add amazing feature'`
|
|
579
|
+
4. Push: `git push origin feat/amazing-feature`
|
|
175
580
|
5. Open a Pull Request
|
|
176
581
|
|
|
177
582
|
---
|
|
178
583
|
|
|
179
|
-
##
|
|
584
|
+
## License
|
|
180
585
|
|
|
181
586
|
MIT © [Umesh Induranga](https://github.com/Umeshinduranga)
|