swagger-to-postman-cli 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Onur runotr13@gmail.com
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/dist/cli.js ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import ora from "ora";
4
+ import pc from "picocolors";
5
+ import { generatePostman } from "./index.js";
6
+ const program = new Command();
7
+ program
8
+ .name("swagger-to-postman")
9
+ .requiredOption("-i, --input <pathOrUrl>", "Swagger/OpenAPI file or URL")
10
+ .option("-o, --output <path>", "Output folder", "./output")
11
+ .option("--sync", "Sync collection to Postman")
12
+ .action(async (opts) => {
13
+ const spinner = ora(pc.cyan("Swagger analiz ediliyor...")).start();
14
+ try {
15
+ await generatePostman({
16
+ input: opts.input,
17
+ output: opts.output,
18
+ sync: opts.sync,
19
+ });
20
+ spinner.succeed(pc.green("Başarıyla tamamlandı!"));
21
+ }
22
+ catch (err) {
23
+ spinner.fail(pc.red(err.message));
24
+ process.exit(1);
25
+ }
26
+ });
27
+ program.parse();
@@ -0,0 +1,90 @@
1
+ import sdk from "postman-collection";
2
+ import * as fs from "fs";
3
+ export class CollectionBuilder {
4
+ collection;
5
+ constructor(title) {
6
+ this.collection = new sdk.Collection({
7
+ info: { name: `${title} - Automated Tests` },
8
+ });
9
+ }
10
+ addRequest(method, urlPath, bodyData, parameters = []) {
11
+ const queryParams = parameters
12
+ .filter((p) => p.in === "query")
13
+ .map((p) => ({
14
+ key: p.name,
15
+ value: `{{${p.name}}}`,
16
+ description: p.description || "",
17
+ }));
18
+ const pathVariables = parameters
19
+ .filter((p) => p.in === "path")
20
+ .map((p) => ({
21
+ key: p.name,
22
+ value: `{{${p.name}}}`,
23
+ description: p.description || "",
24
+ }));
25
+ const requestConfig = {
26
+ method: method.toUpperCase(),
27
+ header: [{ key: "Content-Type", value: "application/json" }],
28
+ url: {
29
+ host: ["{{baseUrl}}"],
30
+ path: urlPath
31
+ .split("/")
32
+ .filter((p) => p !== "")
33
+ .map((p) => p.replace(/{/g, ":").replace(/}/g, "")),
34
+ query: queryParams,
35
+ variable: pathVariables,
36
+ },
37
+ };
38
+ if (bodyData && Object.keys(bodyData).length > 0) {
39
+ requestConfig.body = {
40
+ mode: "raw",
41
+ raw: JSON.stringify(bodyData, null, 2),
42
+ options: { raw: { language: "json" } },
43
+ };
44
+ }
45
+ const newItem = new sdk.Item({
46
+ name: `${method.toUpperCase()} ${urlPath}`,
47
+ request: requestConfig,
48
+ });
49
+ newItem.events.add(new sdk.Event({
50
+ listen: "test",
51
+ script: {
52
+ type: "text/javascript",
53
+ exec: [
54
+ 'pm.test("Status code is 200", function () { pm.response.to.have.status(200); });',
55
+ ],
56
+ },
57
+ }));
58
+ this.collection.items.add(newItem);
59
+ }
60
+ setAuthentication(securitySchemes) {
61
+ if (!securitySchemes)
62
+ return;
63
+ const schemeNames = Object.keys(securitySchemes);
64
+ if (schemeNames.length === 0)
65
+ return;
66
+ const scheme = securitySchemes[schemeNames[0]];
67
+ if (scheme.type === "apiKey") {
68
+ this.collection.auth = new sdk.RequestAuth({
69
+ type: "apikey",
70
+ apikey: [
71
+ { key: "key", value: scheme.name, type: "string" },
72
+ { key: "value", value: "{{apiKey}}", type: "string" },
73
+ { key: "in", value: scheme.in || "header", type: "string" },
74
+ ],
75
+ });
76
+ }
77
+ else if (scheme.type === "http" && scheme.scheme === "bearer") {
78
+ this.collection.auth = new sdk.RequestAuth({
79
+ type: "bearer",
80
+ bearer: [{ key: "token", value: "{{bearerToken}}", type: "string" }],
81
+ });
82
+ }
83
+ }
84
+ saveToFile(fileName) {
85
+ fs.writeFileSync(fileName, JSON.stringify(this.collection.toJSON(), null, 2));
86
+ }
87
+ getCollection() {
88
+ return this.collection;
89
+ }
90
+ }
@@ -0,0 +1,25 @@
1
+ import * as fs from "fs";
2
+ export class EnvironmentBuilder {
3
+ env;
4
+ constructor(title) {
5
+ this.env = {
6
+ name: `${title} - Env`,
7
+ values: [],
8
+ _postman_variable_scope: "environment",
9
+ };
10
+ }
11
+ addVariable(key, value) {
12
+ const exists = this.env.values.find((v) => v.key === key);
13
+ if (!exists) {
14
+ this.env.values.push({
15
+ key,
16
+ value,
17
+ enabled: true,
18
+ type: "default",
19
+ });
20
+ }
21
+ }
22
+ saveToFile(fileName) {
23
+ fs.writeFileSync(fileName, JSON.stringify(this.env, null, 2));
24
+ }
25
+ }
@@ -0,0 +1,29 @@
1
+ import { faker } from "@faker-js/faker";
2
+ export class DataFactory {
3
+ static generate(type, format, fieldName, enumValues) {
4
+ if (enumValues && enumValues.length > 0)
5
+ return faker.helpers.arrayElement(enumValues);
6
+ const lowerFieldName = fieldName?.toLowerCase() || "";
7
+ if (lowerFieldName.includes("email"))
8
+ return faker.internet.email();
9
+ if (lowerFieldName.includes("password"))
10
+ return faker.internet.password();
11
+ if (lowerFieldName.includes("url"))
12
+ return faker.internet.url();
13
+ if (lowerFieldName.includes("id") && type === "integer")
14
+ return faker.number.int({ min: 1, max: 999 });
15
+ switch (type) {
16
+ case "string":
17
+ if (format === "date-time")
18
+ return faker.date.recent().toISOString();
19
+ return faker.lorem.word();
20
+ case "integer":
21
+ case "number":
22
+ return faker.number.int({ min: 1, max: 100 });
23
+ case "boolean":
24
+ return faker.datatype.boolean();
25
+ default:
26
+ return null;
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,20 @@
1
+ import { DataFactory } from "./DataFactory.js";
2
+ export function generateMockData(schema, fieldName = "") {
3
+ if (!schema)
4
+ return null;
5
+ const target = schema.schema ? schema.schema : schema;
6
+ const type = target.type || (target.properties ? "object" : "string");
7
+ if (type === "array") {
8
+ const items = target.items || { type: "string" };
9
+ return [generateMockData(items, fieldName)];
10
+ }
11
+ if (type === "object" || target.properties) {
12
+ const obj = {};
13
+ const props = target.properties || {};
14
+ for (const [key, value] of Object.entries(props)) {
15
+ obj[key] = generateMockData(value, key);
16
+ }
17
+ return obj;
18
+ }
19
+ return DataFactory.generate(type, target.format, fieldName || target.name || target.title, target.enum);
20
+ }
@@ -0,0 +1,32 @@
1
+ import ora from "ora";
2
+ import pc from "picocolors";
3
+ export async function syncToPostman(collectionData) {
4
+ const apiKey = process.env.POSTMAN_API_KEY;
5
+ const collectionId = process.env.COLLECTION_ID;
6
+ if (!apiKey || !collectionId) {
7
+ console.log(pc.yellow("\n⚠️ API Key veya Collection ID bulunamadı, senkronizasyon atlandı."));
8
+ return;
9
+ }
10
+ const spinner = ora(pc.cyan("Postman koleksiyonu gΓΌncelleniyor...")).start();
11
+ try {
12
+ const res = await fetch(`https://api.getpostman.com/collections/${collectionId}`, {
13
+ method: "PUT",
14
+ headers: {
15
+ "X-Api-Key": apiKey,
16
+ "Content-Type": "application/json",
17
+ },
18
+ body: JSON.stringify({
19
+ collection: collectionData,
20
+ }),
21
+ });
22
+ if (!res.ok) {
23
+ const text = await res.text();
24
+ throw new Error(`${res.status} ${res.statusText} - ${text}`);
25
+ }
26
+ spinner.succeed(pc.green("Postman başarıyla güncellendi!"));
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ spinner.fail(pc.red("Postman gΓΌncellenirken hata: " + message));
31
+ }
32
+ }
package/dist/index.js ADDED
@@ -0,0 +1,58 @@
1
+ import fs from "fs";
2
+ import SwaggerParser from "@apidevtools/swagger-parser";
3
+ import { CollectionBuilder } from "./core/CollectionBuilder.js";
4
+ import { EnvironmentBuilder } from "./core/EnvironmentBuilder.js";
5
+ import { SwaggerService } from "./services/SwaggerService.js";
6
+ import { generateMockData } from "./generators/generate-mock-data.js";
7
+ import { syncToPostman } from "./helpers/syncToPostman.js";
8
+ export async function generatePostman({ input, output = "./output", sync = false, }) {
9
+ const api = await SwaggerParser.validate(input);
10
+ const colBuilder = new CollectionBuilder(api.info.title);
11
+ const envBuilder = new EnvironmentBuilder(api.info.title);
12
+ const security = SwaggerService.getSecuritySchemes(api);
13
+ colBuilder.setAuthentication(security);
14
+ const securityStr = JSON.stringify(security || "");
15
+ if (securityStr.includes("apiKey"))
16
+ envBuilder.addVariable("apiKey", "YOUR_KEY");
17
+ if (securityStr.includes("bearer"))
18
+ envBuilder.addVariable("bearerToken", "YOUR_TOKEN");
19
+ envBuilder.addVariable("baseUrl", SwaggerService.getBaseUrl(api));
20
+ for (const [path, pathItem] of Object.entries(api.paths || {})) {
21
+ if (!pathItem)
22
+ continue;
23
+ for (const method of [
24
+ "get",
25
+ "post",
26
+ "put",
27
+ "delete",
28
+ "patch",
29
+ "options",
30
+ "head",
31
+ ]) {
32
+ const operation = pathItem[method];
33
+ if (!operation)
34
+ continue;
35
+ const parameters = operation.parameters || [];
36
+ parameters.forEach((param) => {
37
+ if (param.in !== "body") {
38
+ const mockVal = generateMockData(param, param.name);
39
+ envBuilder.addVariable(param.name, String(mockVal ?? ""));
40
+ }
41
+ });
42
+ let mockBody = {};
43
+ const bodySchema = operation.requestBody?.content?.["application/json"]?.schema ||
44
+ parameters.find((p) => p.in === "body")?.schema;
45
+ if (bodySchema) {
46
+ mockBody = generateMockData(bodySchema);
47
+ }
48
+ colBuilder.addRequest(method, path, mockBody, parameters);
49
+ }
50
+ }
51
+ if (!fs.existsSync(output))
52
+ fs.mkdirSync(output, { recursive: true });
53
+ colBuilder.saveToFile(`${output}/collection.json`);
54
+ envBuilder.saveToFile(`${output}/environment.json`);
55
+ if (sync) {
56
+ await syncToPostman(colBuilder.getCollection());
57
+ }
58
+ }
@@ -0,0 +1,14 @@
1
+ export class SwaggerService {
2
+ static getBaseUrl(api) {
3
+ if (api.servers && api.servers.length > 0)
4
+ return api.servers[0].url;
5
+ if (api.host) {
6
+ const protocol = (api.schemes && api.schemes[0]) || "https";
7
+ return `${protocol}://${api.host}${api.basePath || ""}`;
8
+ }
9
+ return "http://localhost";
10
+ }
11
+ static getSecuritySchemes(api) {
12
+ return api.components?.securitySchemes || api.securityDefinitions || null;
13
+ }
14
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "swagger-to-postman-cli",
3
+ "version": "1.0.1",
4
+ "description": "Generate dynamic Postman collections from Swagger/OpenAPI with Faker.js",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "bin": {
11
+ "swagger-to-postman": "dist/cli.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "clean": "rm -rf dist",
20
+ "build": "npm run clean && tsc && chmod +x dist/cli.js",
21
+ "start": "npx tsx src/cli.ts",
22
+ "prepare": "npm run build",
23
+ "prelink": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "swagger",
27
+ "openapi",
28
+ "postman",
29
+ "faker",
30
+ "testing",
31
+ "automation",
32
+ "mock-data"
33
+ ],
34
+ "author": "Onur runotr13@gmail.com",
35
+ "license": "ISC",
36
+ "dependencies": {
37
+ "@apidevtools/swagger-parser": "^12.1.0",
38
+ "@faker-js/faker": "^10.2.0",
39
+ "commander": "^14.0.2",
40
+ "openapi-types": "^12.1.3",
41
+ "ora": "^9.0.0",
42
+ "picocolors": "^1.1.1",
43
+ "postman-collection": "^5.2.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^25.0.8",
47
+ "@types/postman-collection": "^3.5.11",
48
+ "ts-node": "^10.9.2",
49
+ "tsx": "^4.21.0",
50
+ "typescript": "^5.9.3"
51
+ }
52
+ }
package/readme.md ADDED
@@ -0,0 +1,95 @@
1
+ # Swagger to Postman (CLI Tool) πŸš€
2
+ [![Update Postman Collection](https://github.com/runotr13/swagger-to-postman/actions/workflows/postman-sync.yml/badge.svg)](https://github.com/runotr13/swagger-to-postman/actions/workflows/postman-sync.yml)
3
+ ![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white)
4
+ ![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white)
5
+ ![GitHub Actions](https://img.shields.io/badge/github%20actions-%232671E5.svg?style=for-the-badge&logo=githubactions&logoColor=white)
6
+
7
+ Generate dynamic, automated Postman collections and environments directly from your Swagger/OpenAPI documentation. This tool leverages **Faker.js** to populate requests with realistic mock data, ensuring a robust and production-ready testing workflow.
8
+
9
+ ---
10
+
11
+ ## πŸ›  Features
12
+
13
+ - **Smart Mocking:** Automatically detects field names like `email`, `name`, `id`, and `password` to generate context-aware data.
14
+ - **Recursive Parsing:** Deeply crawls nested objects and arrays in your Swagger schemas.
15
+ - **Postman SDK:** Built on top of the official `postman-collection` library.
16
+ - **Environment Automation:** Auto-generates `baseUrl` and security variables (API Key, Bearer Token).
17
+ - **CI/CD Ready:** Built-in support for synchronizing collections directly to Postman Cloud.
18
+
19
+ ---
20
+
21
+ ## πŸ“‚ Project Structure
22
+
23
+ The project is organized following the **Single Responsibility Principle**:
24
+
25
+ ```text
26
+ src/
27
+ β”œβ”€β”€ core/ # Postman SDK logic (Collection & Environment)
28
+ β”œβ”€β”€ generators/ # Mock data engine and schema traversal
29
+ β”œβ”€β”€ helpers/ # Utility functions (e.g., Postman Cloud Sync)
30
+ β”œβ”€β”€ services/ # Swagger analysis and business logic
31
+ β”œβ”€β”€ cli.ts # CLI entry point
32
+ └── index.ts # Public library API
33
+ ```
34
+
35
+ ## πŸ“¦ npm Usage
36
+
37
+ ### Run without install
38
+
39
+ ```bash
40
+ npx swagger-to-postman -i ./swagger.json
41
+ ```
42
+
43
+ ### Global install
44
+
45
+ ```bash
46
+ npm install -g swagger-to-postman
47
+ swagger-to-postman -i ./swagger.json
48
+ ```
49
+
50
+ ### Local dependency
51
+
52
+ ```bash
53
+ npm install swagger-to-postman
54
+ npx swagger-to-postman -i ./swagger.json
55
+ ```
56
+
57
+ ## Build and Link locally:
58
+
59
+ ```bash
60
+ npm run build
61
+ npm link
62
+ ```
63
+
64
+ ## Development
65
+
66
+ ```bash
67
+ npm run start -- -i ./swagger.json -o ./output
68
+ ```
69
+
70
+ ## Running the Tool
71
+
72
+ ```bash
73
+ # Using a local file
74
+ swagger-to-postman -i ./swagger.json -o ./output
75
+
76
+ # Using a remote URL
77
+ swagger-to-postman -i https://petstore.swagger.io/v2/swagger.json -o ./petstore-output
78
+ ```
79
+
80
+ ## πŸ“– CLI Arguments
81
+
82
+ | Argument | Shorthand | Description | Default |
83
+ | :--------- | :-------- | :------------------------------------------------------ | :--------- |
84
+ | `--input` | `-i` | **(Required)** Path to local swagger.json or remote URL | N/A |
85
+ | `--output` | `-o` | Target directory for generated files | `./output` |
86
+
87
+ ## πŸ“€ Output
88
+
89
+ The tool generates the following files:
90
+
91
+ ```text
92
+ output/
93
+ β”œβ”€β”€ collection.json # Postman Collection
94
+ └── environment.json # Postman Environment
95
+ ```