Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit 3f86a19

Browse files
committed
feat: allow add operation id to the request
1 parent 66916ec commit 3f86a19

11 files changed

Lines changed: 526 additions & 21 deletions

File tree

docs/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ The third parameter used in the library method is an `options` object containing
133133
| [replaceVars](#replacevars-boolean) | Boolean value to indicate if postman variables should be replaced.|
134134
| [additionalVars](#additionalvars-object) | Object to provide additional values for variables replacement.|
135135
| [outputFormat](#outputformat-string) | Indicate the format of the output document. |
136+
| [operationId](#operationid-string) | Indicate how to provide the value for `operationId` field. |
136137

137138
### info (Object)
138139

@@ -361,6 +362,22 @@ By default all parameters in the postman collection that has the field `"disable
361362

362363
Please have a look to the [Parameters parsing](#parameters-parsing) section about duplicated parameters names in Headers and Query, this will apply also to the disabled parameters when using this feature.
363364

365+
### operationId (string)
366+
367+
In OpenAPI the [operationId](https://swagger.io/specification/#operation-object) is a unique id that is used mainly for Tools and libraries to uniquely identify an operation, with this option you can indicate the strategy to provide this value for each request operation, the possible values are:
368+
369+
| Option | Description |
370+
|------------------|------------------------------------------------------------------------------------|
371+
| `off` | Default. No `operationId` will be added. |
372+
| `auto` | The field `name` of the request will transformed as [Camel case](https://es.wikipedia.org/wiki/Camel_ca) and used as `operationId`. |
373+
| `brackets` | Will look for a name between brackets in the fields `name` of the request and use this as `operationId`. |
374+
375+
As an example of option `auto` if you have in a postman collection a request with name `Create new User` the resulting operation id will be `createNewUser`.
376+
377+
To use option `brackets` you should add the desired operation id between brackets in the name of the request, so for example if you use as request name `Create new User [newUser]`, the text `newUser` will be used as operation id, the library automatically will remove the literal `[newUser]` from the name and will no appear in the `summary` field in the OpenAPI yaml.
378+
379+
> **Note about duplications:** As described in OpenAPI about the operationId, "The id MUST be unique among all operations described in the API." but the library does not ensure the uniqueness, so before do the conversion check that you are using unique operations ids for each request in your collection.
380+
364381
</div></div>
365382
<div class="tilted-section"><div markdown="1">
366383

lib/index.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ const { parseMdTable } = require('./md-utils')
66
const { version } = require('../package.json')
77
const replacePostmanVariables = require('./var-replacer')
88
const jsonc = require('jsonc-parser')
9+
const camelCase = require('lodash.camelcase')
910

1011
async function postmanToOpenApi (input, output, {
1112
info = {}, defaultTag = 'default', pathDepth = 0,
1213
auth: optsAuth, servers, externalDocs = {}, folders = {},
1314
responseHeaders = true, replaceVars = false, additionalVars = {}, outputFormat = 'yaml',
14-
disabledParams = { includeQuery: false, includeHeader: false }
15+
disabledParams = { includeQuery: false, includeHeader: false }, operationId = 'off'
1516
} = {}) {
1617
// TODO validate?
1718
let collectionFile = await resolveInput(input)
@@ -40,17 +41,20 @@ async function postmanToOpenApi (input, output, {
4041
if (element != null) {
4142
const {
4243
request: { url, method, body, description: rawDesc, header = [], auth },
43-
name: summary, tag = defaultTag, event: events, response
44+
name, tag = defaultTag, event: events, response
4445
} = element
4546
const { path, query, protocol, host, port, valid, pathVars } = scrapeURL(url)
4647
if (valid) {
48+
// Remove from name the possible operation id between brackets
49+
const summary = name.replace(/ \[(.*?)\]/gi, '')
4750
domains.add(calculateDomains(protocol, host, port))
4851
const joinedPath = calculatePath(path, pathDepth)
4952
if (!paths[joinedPath]) paths[joinedPath] = {}
5053
const { description, paramsMeta } = descriptionParse(rawDesc)
5154
paths[joinedPath][method.toLowerCase()] = {
5255
tags: [tag],
5356
summary,
57+
...(calculateOperationId(operationId, name, summary)),
5458
...(description ? { description } : {}),
5559
...parseBody(body, method),
5660
...parseOperationAuth(auth, securitySchemes, optsAuth),
@@ -610,6 +614,32 @@ function isRequired (text) {
610614
return /\[required\]/gi.test(text)
611615
}
612616

617+
/**
618+
* calculate the operationId based on the user selected `mode`
619+
* @param {*} mode - mode to calculate the operation id between `off`, `auto` or `brackets`
620+
* @param {*} name - field name of the request/operation in the postman collection without modify.
621+
* @param {*} summary - calculated summary of the operation that will be used in the OpenAPI spec.
622+
* @returns an operation id
623+
*/
624+
function calculateOperationId (mode, name, summary) {
625+
let operationId
626+
switch (mode) {
627+
case 'off':
628+
break
629+
case 'auto':
630+
operationId = camelCase(summary)
631+
break
632+
case 'brackets': {
633+
const matches = name.match(/\[([^()]*)\]/)
634+
operationId = matches ? matches[1] : undefined
635+
break
636+
}
637+
default: // Unknown value in the operationId option
638+
break
639+
}
640+
return operationId ? { operationId } : {}
641+
}
642+
613643
postmanToOpenApi.version = version
614644

615645
module.exports = postmanToOpenApi

package-lock.json

Lines changed: 60 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postman-to-openapi",
3-
"version": "2.8.0",
3+
"version": "2.9.0",
44
"description": "Convert postman collection to OpenAPI spec",
55
"main": "lib/index.js",
66
"types": "types/index.d.ts",
@@ -90,6 +90,7 @@
9090
"commander": "^8.3.0",
9191
"js-yaml": "^4.1.0",
9292
"jsonc-parser": "3.2.0",
93+
"lodash.camelcase": "^4.3.0",
9394
"marked": "^4.2.2",
9495
"mustache": "^4.2.0"
9596
},

test/index.spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ const EXPECTED_DISABLED_PARAMS_DEFAULT = readFileSync('./test/resources/output/D
6666
const EXPECTED_DISABLED_PARAMS_ALL = readFileSync('./test/resources/output/DisabledParamsAll.yml', 'utf8')
6767
const EXPECTED_DISABLED_PARAMS_QUERY = readFileSync('./test/resources/output/DisabledParamsQuery.yml', 'utf8')
6868
const EXPECTED_DISABLED_PARAMS_HEADER = readFileSync('./test/resources/output/DisabledParamsHeader.yml', 'utf8')
69+
const EXPECTED_OPERATIONS_IDS = readFileSync('./test/resources/output/OperationIds.yml', 'utf8')
70+
const EXPECTED_OPERATIONS_IDS_AUTO = readFileSync('./test/resources/output/OperationIdsAuto.yml', 'utf8')
71+
const EXPECTED_OPERATIONS_IDS_BRACKETS = readFileSync('./test/resources/output/OperationIdsBrackets.yml', 'utf8')
6972

7073
const AUTH_DEFINITIONS = {
7174
myCustomAuth: {
@@ -130,6 +133,7 @@ describe('Library specs', function () {
130133
const COLLECTION_RESPONSES_EMPTY = `./test/resources/input/${version}/ResponsesEmpty.json`
131134
const COLLECTION_JSON_COMMENTS = `./test/resources/input/${version}/JsonComments.json`
132135
const COLLECTION_DISABLED = `./test/resources/input/${version}/DisabledParams.json`
136+
const COLLECTION_OPERATION_IDS = `./test/resources/input/${version}/OperationIds.json`
133137

134138
it('should work with a basic transform', async function () {
135139
const result = await postmanToOpenApi(COLLECTION_BASIC, OUTPUT_PATH, {})
@@ -535,6 +539,26 @@ describe('Library specs', function () {
535539
})
536540
equal(result, EXPECTED_DISABLED_PARAMS_HEADER)
537541
})
542+
543+
it('should not add `operationId` by default', async function () {
544+
const result = await postmanToOpenApi(COLLECTION_OPERATION_IDS, OUTPUT_PATH)
545+
equal(result, EXPECTED_OPERATIONS_IDS)
546+
})
547+
548+
it('should include `operationId` when `auto` is selected', async function () {
549+
const result = await postmanToOpenApi(COLLECTION_OPERATION_IDS, OUTPUT_PATH, { operationId: 'auto' })
550+
equal(result, EXPECTED_OPERATIONS_IDS_AUTO)
551+
})
552+
553+
it('should include `operationId` when `brackets` is selected', async function () {
554+
const result = await postmanToOpenApi(COLLECTION_OPERATION_IDS, OUTPUT_PATH, { operationId: 'brackets' })
555+
equal(result, EXPECTED_OPERATIONS_IDS_BRACKETS)
556+
})
557+
558+
it('should not add `operationId` if option is unknown', async function () {
559+
const result = await postmanToOpenApi(COLLECTION_OPERATION_IDS, OUTPUT_PATH, { operationId: 'banana' })
560+
equal(result, EXPECTED_OPERATIONS_IDS)
561+
})
538562
})
539563
})
540564

0 commit comments

Comments
 (0)