@cocaxcode/api-testing-mcp 0.8.2 → 0.9.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 +63 -12
- package/dist/index.js +249 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<h1 align="center">@cocaxcode/api-testing-mcp</h1>
|
|
3
3
|
<p align="center">
|
|
4
4
|
<strong>The most complete API testing MCP server available.</strong><br/>
|
|
5
|
-
|
|
5
|
+
29 tools · Zero config · Zero dependencies · Everything runs inside your AI conversation.
|
|
6
6
|
</p>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<a href="https://www.npmjs.com/package/@cocaxcode/api-testing-mcp"><img src="https://img.shields.io/npm/dm/@cocaxcode/api-testing-mcp.svg?style=flat-square" alt="npm downloads" /></a>
|
|
12
12
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="License" /></a>
|
|
13
13
|
<img src="https://img.shields.io/badge/node-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node" />
|
|
14
|
-
<img src="https://img.shields.io/badge/tools-
|
|
15
|
-
<img src="https://img.shields.io/badge/tests-
|
|
14
|
+
<img src="https://img.shields.io/badge/tools-29-blueviolet?style=flat-square" alt="29 tools" />
|
|
15
|
+
<img src="https://img.shields.io/badge/tests-96-brightgreen?style=flat-square" alt="96 tests" />
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
## What is this?
|
|
31
31
|
|
|
32
|
-
An [MCP server](https://modelcontextprotocol.io) that gives your AI assistant the ability to **test, validate, mock, chain, diff, load-test, and manage** any API — all from natural language.
|
|
32
|
+
An [MCP server](https://modelcontextprotocol.io) that gives your AI assistant the ability to **test, validate, mock, chain, diff, load-test, export to Postman, and manage** any API — all from natural language.
|
|
33
33
|
|
|
34
34
|
You describe what you need. The AI figures out the rest.
|
|
35
35
|
|
|
@@ -47,7 +47,7 @@ There are other API testing MCP servers out there. Here's why this one is differ
|
|
|
47
47
|
|
|
48
48
|
| Capability | @cocaxcode/api-testing-mcp | Others |
|
|
49
49
|
|---|:---:|:---:|
|
|
50
|
-
| HTTP requests with auth |
|
|
50
|
+
| HTTP requests with auth | 29 tools | 1-11 tools |
|
|
51
51
|
| Assertions (eq, neq, gt, lt, contains, exists, type...) | 10 operators | Status code only or none |
|
|
52
52
|
| Request flows with variable extraction | `flow_run` with `extract` | Not available |
|
|
53
53
|
| Collections with tags and CRUD | Full CRUD + tag filtering | Import from Postman or none |
|
|
@@ -57,6 +57,7 @@ There are other API testing MCP servers out there. Here's why this one is differ
|
|
|
57
57
|
| Load testing with percentiles | p50/p95/p99 + req/s | Basic or none |
|
|
58
58
|
| Response diffing | Field-by-field comparison | Not available |
|
|
59
59
|
| Bulk testing by tag | Collection-wide pass/fail | Not available |
|
|
60
|
+
| **Postman export (collection + environment)** | **Files ready to import** | **Not available** |
|
|
60
61
|
| cURL export | With resolved variables | Not available |
|
|
61
62
|
| Project-scoped environments | Per-directory context | Not available |
|
|
62
63
|
| External dependencies | **Zero** — just Node.js | Playwright, Jest, pytest... |
|
|
@@ -182,6 +183,8 @@ You don't need to memorize tool names, parameters, or JSON structures — just t
|
|
|
182
183
|
| *"How fast is the health endpoint under load?"* | Fires 50 concurrent requests, reports p50/p95/p99 latencies |
|
|
183
184
|
| *"Run all my saved smoke tests"* | Executes every request tagged `smoke`, reports pass/fail |
|
|
184
185
|
| *"Export the create-user request as curl"* | Builds a ready-to-paste cURL command with resolved variables |
|
|
186
|
+
| *"Export my collection to Postman"* | Writes a `.postman_collection.json` file ready to import |
|
|
187
|
+
| *"Export the dev environment for Postman"* | Writes a `.postman_environment.json` file ready to import |
|
|
185
188
|
| *"Compare the users endpoint between dev and prod"* | Hits both URLs, diffs status codes, body, and timing |
|
|
186
189
|
| *"Switch to the production environment"* | Changes active env — all subsequent requests use prod URLs and tokens |
|
|
187
190
|
|
|
@@ -396,6 +399,54 @@ BULK TEST — 8/8 passed | 1.2s total
|
|
|
396
399
|
login — POST /auth/login → 200 (156ms)
|
|
397
400
|
```
|
|
398
401
|
|
|
402
|
+
### Postman Export
|
|
403
|
+
|
|
404
|
+
Export your saved requests and environments as Postman-compatible JSON files. The files are written to a `postman/` folder in your project, ready to import in Postman.
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
"Export my collection to Postman"
|
|
408
|
+
"Export only the smoke tests to Postman"
|
|
409
|
+
"Export the dev environment for Postman"
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**What you get:**
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
your-project/
|
|
416
|
+
└── postman/
|
|
417
|
+
├── my-api.postman_collection.json ← Import in Postman: File → Import
|
|
418
|
+
└── dev.postman_environment.json ← Import in Postman: File → Import
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Collection features:**
|
|
422
|
+
- Requests grouped in **folders by tag** (smoke, auth, users, etc.)
|
|
423
|
+
- Auth (Bearer, API Key, Basic) mapped to Postman's native auth format
|
|
424
|
+
- `{{variables}}` preserved as-is (Postman uses the same syntax)
|
|
425
|
+
- Headers, query params, and JSON body included
|
|
426
|
+
- Collection variables from your active environment
|
|
427
|
+
|
|
428
|
+
**Environment features:**
|
|
429
|
+
- All variables exported with `enabled: true`
|
|
430
|
+
- Postman-compatible format (`_postman_variable_scope: "environment"`)
|
|
431
|
+
- Works with any environment (active or by name)
|
|
432
|
+
|
|
433
|
+
<details>
|
|
434
|
+
<summary>Example: exporting with a specific tag</summary>
|
|
435
|
+
|
|
436
|
+
```
|
|
437
|
+
You: "Export my smoke tests to Postman as 'Smoke Tests'"
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
This creates `postman/smoke-tests.postman_collection.json` with only the requests tagged `smoke`, grouped in folders.
|
|
441
|
+
|
|
442
|
+
You can also specify a custom output directory:
|
|
443
|
+
|
|
444
|
+
```
|
|
445
|
+
You: "Export my collection to Postman in the exports folder"
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
</details>
|
|
449
|
+
|
|
399
450
|
### cURL Export
|
|
400
451
|
|
|
401
452
|
Convert any saved request into a ready-to-paste cURL command with resolved variables.
|
|
@@ -443,7 +494,7 @@ Resolution order: project-specific environment → global active environment.
|
|
|
443
494
|
|
|
444
495
|
## Tool Reference
|
|
445
496
|
|
|
446
|
-
|
|
497
|
+
29 tools organized in 8 categories:
|
|
447
498
|
|
|
448
499
|
| Category | Tools | Count |
|
|
449
500
|
|----------|-------|-------|
|
|
@@ -454,7 +505,7 @@ Resolution order: project-specific environment → global active environment.
|
|
|
454
505
|
| **Environments** | `env_create` `env_list` `env_set` `env_get` `env_switch` `env_rename` `env_delete` `env_spec` `env_project_clear` `env_project_list` | 10 |
|
|
455
506
|
| **API Specs** | `api_import` `api_spec_list` `api_endpoints` `api_endpoint_detail` | 4 |
|
|
456
507
|
| **Mock** | `mock` | 1 |
|
|
457
|
-
| **Utilities** | `load_test` `export_curl` `diff_responses` `bulk_test` |
|
|
508
|
+
| **Utilities** | `load_test` `export_curl` `diff_responses` `bulk_test` `export_postman_collection` `export_postman_environment` | 6 |
|
|
458
509
|
|
|
459
510
|
You don't need to call these tools directly. Just describe what you want and the AI picks the right one.
|
|
460
511
|
|
|
@@ -490,14 +541,14 @@ Override the default directory in your MCP config:
|
|
|
490
541
|
Built for reliability and testability:
|
|
491
542
|
|
|
492
543
|
- **Zero runtime dependencies** — only `@modelcontextprotocol/sdk` and `zod`
|
|
493
|
-
- **
|
|
544
|
+
- **96 integration tests** with mocked fetch (no network calls in CI)
|
|
494
545
|
- **Factory pattern** — `createServer(storageDir?)` for isolated test instances
|
|
495
546
|
- **Strict TypeScript** — zero `any`, full type coverage
|
|
496
|
-
- **<
|
|
547
|
+
- **< 95KB** bundled output via tsup
|
|
497
548
|
|
|
498
549
|
```
|
|
499
550
|
src/
|
|
500
|
-
├── tools/ #
|
|
551
|
+
├── tools/ # 29 MCP tool handlers (one file per category)
|
|
501
552
|
├── lib/ # Business logic (no MCP dependency)
|
|
502
553
|
│ ├── http-client # fetch wrapper with timing
|
|
503
554
|
│ ├── storage # JSON file storage engine
|
|
@@ -506,7 +557,7 @@ src/
|
|
|
506
557
|
│ ├── path # Dot-notation accessor (body.data.0.id)
|
|
507
558
|
│ ├── interpolation # {{variable}} resolver
|
|
508
559
|
│ └── openapi-parser # $ref + allOf/oneOf/anyOf resolution
|
|
509
|
-
└── __tests__/ # 10 test suites,
|
|
560
|
+
└── __tests__/ # 10 test suites, 96 tests
|
|
510
561
|
```
|
|
511
562
|
|
|
512
563
|
---
|
|
@@ -527,7 +578,7 @@ src/
|
|
|
527
578
|
git clone https://github.com/cocaxcode/api-testing-mcp.git
|
|
528
579
|
cd api-testing-mcp
|
|
529
580
|
npm install
|
|
530
|
-
npm test #
|
|
581
|
+
npm test # 96 tests across 10 suites
|
|
531
582
|
npm run build # ESM bundle via tsup
|
|
532
583
|
npm run typecheck # Strict TypeScript
|
|
533
584
|
```
|
package/dist/index.js
CHANGED
|
@@ -424,7 +424,8 @@ function interpolateRequest(config, variables) {
|
|
|
424
424
|
url: interpolateString(config.url, variables),
|
|
425
425
|
headers: interpolateRecord(config.headers, variables),
|
|
426
426
|
query: interpolateRecord(config.query, variables),
|
|
427
|
-
body: config.body !== void 0 ? interpolateValue(config.body, variables) : void 0
|
|
427
|
+
body: config.body !== void 0 ? interpolateValue(config.body, variables) : void 0,
|
|
428
|
+
auth: config.auth ? interpolateValue(config.auth, variables) : void 0
|
|
428
429
|
};
|
|
429
430
|
}
|
|
430
431
|
|
|
@@ -1859,6 +1860,8 @@ function registerFlowTool(server, storage) {
|
|
|
1859
1860
|
|
|
1860
1861
|
// src/tools/utilities.ts
|
|
1861
1862
|
import { z as z8 } from "zod";
|
|
1863
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
1864
|
+
import { join as join2 } from "path";
|
|
1862
1865
|
function registerUtilityTools(server, storage) {
|
|
1863
1866
|
server.tool(
|
|
1864
1867
|
"export_curl",
|
|
@@ -2138,6 +2141,251 @@ ${curlCommand}`
|
|
|
2138
2141
|
}
|
|
2139
2142
|
}
|
|
2140
2143
|
);
|
|
2144
|
+
server.tool(
|
|
2145
|
+
"export_postman_collection",
|
|
2146
|
+
"Exporta los requests guardados como una Postman Collection v2.1 (JSON). Escribe el archivo en disco, importable directamente en Postman.",
|
|
2147
|
+
{
|
|
2148
|
+
name: z8.string().optional().describe('Nombre de la colecci\xF3n (default: "API Testing Collection")'),
|
|
2149
|
+
tag: z8.string().optional().describe("Filtrar requests por tag"),
|
|
2150
|
+
output_dir: z8.string().optional().describe("Directorio donde guardar el archivo (default: ./postman/)"),
|
|
2151
|
+
resolve_variables: z8.boolean().optional().describe("Resolver {{variables}} del entorno activo (default: false)")
|
|
2152
|
+
},
|
|
2153
|
+
async (params) => {
|
|
2154
|
+
try {
|
|
2155
|
+
const collections = await storage.listCollections(params.tag);
|
|
2156
|
+
if (collections.length === 0) {
|
|
2157
|
+
return {
|
|
2158
|
+
content: [
|
|
2159
|
+
{
|
|
2160
|
+
type: "text",
|
|
2161
|
+
text: params.tag ? `No hay requests guardados con tag '${params.tag}'.` : "No hay requests guardados en la colecci\xF3n."
|
|
2162
|
+
}
|
|
2163
|
+
]
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
const resolveVars = params.resolve_variables ?? false;
|
|
2167
|
+
const variables = resolveVars ? await storage.getActiveVariables() : {};
|
|
2168
|
+
const savedRequests = [];
|
|
2169
|
+
for (const item of collections) {
|
|
2170
|
+
const saved = await storage.getCollection(item.name);
|
|
2171
|
+
if (saved) savedRequests.push(saved);
|
|
2172
|
+
}
|
|
2173
|
+
const tagged = /* @__PURE__ */ new Map();
|
|
2174
|
+
const untagged = [];
|
|
2175
|
+
for (const saved of savedRequests) {
|
|
2176
|
+
if (saved.tags && saved.tags.length > 0) {
|
|
2177
|
+
const tag = saved.tags[0];
|
|
2178
|
+
if (!tagged.has(tag)) tagged.set(tag, []);
|
|
2179
|
+
tagged.get(tag).push(saved);
|
|
2180
|
+
} else {
|
|
2181
|
+
untagged.push(saved);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
const items = [];
|
|
2185
|
+
for (const [tag, requests] of tagged) {
|
|
2186
|
+
items.push({
|
|
2187
|
+
name: tag,
|
|
2188
|
+
item: requests.map((r) => buildPostmanItem(r, variables, resolveVars))
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
for (const saved of untagged) {
|
|
2192
|
+
items.push(buildPostmanItem(saved, variables, resolveVars));
|
|
2193
|
+
}
|
|
2194
|
+
const activeVars = await storage.getActiveVariables();
|
|
2195
|
+
const collectionVars = Object.entries(activeVars).map(([key, value]) => ({
|
|
2196
|
+
key,
|
|
2197
|
+
value,
|
|
2198
|
+
type: "string"
|
|
2199
|
+
}));
|
|
2200
|
+
const collectionName = params.name ?? "API Testing Collection";
|
|
2201
|
+
const postmanCollection = {
|
|
2202
|
+
info: {
|
|
2203
|
+
name: collectionName,
|
|
2204
|
+
schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
|
2205
|
+
},
|
|
2206
|
+
item: items,
|
|
2207
|
+
variable: collectionVars
|
|
2208
|
+
};
|
|
2209
|
+
const json = JSON.stringify(postmanCollection, null, 2);
|
|
2210
|
+
const outputDir = params.output_dir ?? join2(process.cwd(), "postman");
|
|
2211
|
+
await mkdir2(outputDir, { recursive: true });
|
|
2212
|
+
const fileName = collectionName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") + ".postman_collection.json";
|
|
2213
|
+
const filePath = join2(outputDir, fileName);
|
|
2214
|
+
await writeFile2(filePath, json, "utf-8");
|
|
2215
|
+
return {
|
|
2216
|
+
content: [
|
|
2217
|
+
{
|
|
2218
|
+
type: "text",
|
|
2219
|
+
text: `Postman Collection v2.1 exportada (${savedRequests.length} requests).
|
|
2220
|
+
|
|
2221
|
+
Archivo: ${filePath}
|
|
2222
|
+
|
|
2223
|
+
Importa este archivo en Postman: File \u2192 Import \u2192 selecciona el archivo.`
|
|
2224
|
+
}
|
|
2225
|
+
]
|
|
2226
|
+
};
|
|
2227
|
+
} catch (error) {
|
|
2228
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2229
|
+
return {
|
|
2230
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
2231
|
+
isError: true
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
);
|
|
2236
|
+
server.tool(
|
|
2237
|
+
"export_postman_environment",
|
|
2238
|
+
"Exporta un entorno como Postman Environment (JSON). Escribe el archivo en disco, importable directamente en Postman.",
|
|
2239
|
+
{
|
|
2240
|
+
name: z8.string().optional().describe("Nombre del entorno a exportar (default: entorno activo)"),
|
|
2241
|
+
output_dir: z8.string().optional().describe("Directorio donde guardar el archivo (default: ./postman/)")
|
|
2242
|
+
},
|
|
2243
|
+
async (params) => {
|
|
2244
|
+
try {
|
|
2245
|
+
let envName = params.name;
|
|
2246
|
+
if (!envName) {
|
|
2247
|
+
envName = await storage.getActiveEnvironment() ?? void 0;
|
|
2248
|
+
if (!envName) {
|
|
2249
|
+
return {
|
|
2250
|
+
content: [
|
|
2251
|
+
{
|
|
2252
|
+
type: "text",
|
|
2253
|
+
text: 'No hay entorno activo. Especifica un nombre con el par\xE1metro "name".'
|
|
2254
|
+
}
|
|
2255
|
+
],
|
|
2256
|
+
isError: true
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
const env = await storage.getEnvironment(envName);
|
|
2261
|
+
if (!env) {
|
|
2262
|
+
return {
|
|
2263
|
+
content: [
|
|
2264
|
+
{
|
|
2265
|
+
type: "text",
|
|
2266
|
+
text: `Entorno '${envName}' no encontrado.`
|
|
2267
|
+
}
|
|
2268
|
+
],
|
|
2269
|
+
isError: true
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
const postmanEnv = {
|
|
2273
|
+
name: env.name,
|
|
2274
|
+
values: Object.entries(env.variables).map(([key, value]) => ({
|
|
2275
|
+
key,
|
|
2276
|
+
value,
|
|
2277
|
+
type: "default",
|
|
2278
|
+
enabled: true
|
|
2279
|
+
})),
|
|
2280
|
+
_postman_variable_scope: "environment"
|
|
2281
|
+
};
|
|
2282
|
+
const json = JSON.stringify(postmanEnv, null, 2);
|
|
2283
|
+
const outputDir = params.output_dir ?? join2(process.cwd(), "postman");
|
|
2284
|
+
await mkdir2(outputDir, { recursive: true });
|
|
2285
|
+
const fileName = env.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") + ".postman_environment.json";
|
|
2286
|
+
const filePath = join2(outputDir, fileName);
|
|
2287
|
+
await writeFile2(filePath, json, "utf-8");
|
|
2288
|
+
return {
|
|
2289
|
+
content: [
|
|
2290
|
+
{
|
|
2291
|
+
type: "text",
|
|
2292
|
+
text: `Postman Environment "${env.name}" exportado (${Object.keys(env.variables).length} variables).
|
|
2293
|
+
|
|
2294
|
+
Archivo: ${filePath}
|
|
2295
|
+
|
|
2296
|
+
Importa este archivo en Postman: File \u2192 Import \u2192 selecciona el archivo.`
|
|
2297
|
+
}
|
|
2298
|
+
]
|
|
2299
|
+
};
|
|
2300
|
+
} catch (error) {
|
|
2301
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2302
|
+
return {
|
|
2303
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
2304
|
+
isError: true
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
function buildPostmanItem(saved, variables, resolveVars) {
|
|
2311
|
+
let config = saved.request;
|
|
2312
|
+
if (resolveVars) {
|
|
2313
|
+
const resolvedUrl = resolveUrl(config.url, variables);
|
|
2314
|
+
config = { ...config, url: resolvedUrl };
|
|
2315
|
+
config = interpolateRequest(config, variables);
|
|
2316
|
+
}
|
|
2317
|
+
const item = {
|
|
2318
|
+
name: saved.name,
|
|
2319
|
+
request: buildPostmanRequest(config)
|
|
2320
|
+
};
|
|
2321
|
+
return item;
|
|
2322
|
+
}
|
|
2323
|
+
function buildPostmanRequest(config) {
|
|
2324
|
+
const request = {
|
|
2325
|
+
method: config.method,
|
|
2326
|
+
header: buildPostmanHeaders(config.headers),
|
|
2327
|
+
url: buildPostmanUrl(config.url, config.query)
|
|
2328
|
+
};
|
|
2329
|
+
if (config.body !== void 0 && config.body !== null) {
|
|
2330
|
+
request.body = {
|
|
2331
|
+
mode: "raw",
|
|
2332
|
+
raw: typeof config.body === "string" ? config.body : JSON.stringify(config.body, null, 2),
|
|
2333
|
+
options: { raw: { language: "json" } }
|
|
2334
|
+
};
|
|
2335
|
+
const headers = request.header;
|
|
2336
|
+
if (!headers.some((h) => h.key.toLowerCase() === "content-type")) {
|
|
2337
|
+
headers.push({ key: "Content-Type", value: "application/json" });
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
if (config.auth) {
|
|
2341
|
+
request.auth = buildPostmanAuth(config.auth);
|
|
2342
|
+
}
|
|
2343
|
+
return request;
|
|
2344
|
+
}
|
|
2345
|
+
function buildPostmanHeaders(headers) {
|
|
2346
|
+
if (!headers) return [];
|
|
2347
|
+
return Object.entries(headers).map(([key, value]) => ({ key, value }));
|
|
2348
|
+
}
|
|
2349
|
+
function buildPostmanUrl(rawUrl, query) {
|
|
2350
|
+
const url = { raw: rawUrl };
|
|
2351
|
+
const match = rawUrl.match(/^(https?):\/\/([^/]+)(\/.*)?$/);
|
|
2352
|
+
if (match) {
|
|
2353
|
+
url.protocol = match[1];
|
|
2354
|
+
url.host = match[2].split(".");
|
|
2355
|
+
url.path = match[3] ? match[3].slice(1).split("/") : [];
|
|
2356
|
+
}
|
|
2357
|
+
if (query && Object.keys(query).length > 0) {
|
|
2358
|
+
url.query = Object.entries(query).map(([key, value]) => ({ key, value }));
|
|
2359
|
+
const queryStr = Object.entries(query).map(([k, v]) => `${k}=${v}`).join("&");
|
|
2360
|
+
url.raw = rawUrl + (rawUrl.includes("?") ? "&" : "?") + queryStr;
|
|
2361
|
+
}
|
|
2362
|
+
return url;
|
|
2363
|
+
}
|
|
2364
|
+
function buildPostmanAuth(auth) {
|
|
2365
|
+
switch (auth.type) {
|
|
2366
|
+
case "bearer":
|
|
2367
|
+
return {
|
|
2368
|
+
type: "bearer",
|
|
2369
|
+
bearer: [{ key: "token", value: auth.token ?? "", type: "string" }]
|
|
2370
|
+
};
|
|
2371
|
+
case "api-key":
|
|
2372
|
+
return {
|
|
2373
|
+
type: "apikey",
|
|
2374
|
+
apikey: [
|
|
2375
|
+
{ key: "key", value: auth.key ?? "", type: "string" },
|
|
2376
|
+
{ key: "value", value: auth.header ?? "X-API-Key", type: "string" },
|
|
2377
|
+
{ key: "in", value: "header", type: "string" }
|
|
2378
|
+
]
|
|
2379
|
+
};
|
|
2380
|
+
case "basic":
|
|
2381
|
+
return {
|
|
2382
|
+
type: "basic",
|
|
2383
|
+
basic: [
|
|
2384
|
+
{ key: "username", value: auth.username ?? "", type: "string" },
|
|
2385
|
+
{ key: "password", value: auth.password ?? "", type: "string" }
|
|
2386
|
+
]
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2141
2389
|
}
|
|
2142
2390
|
|
|
2143
2391
|
// src/tools/mock.ts
|