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

Commit

Permalink
Merge pull request #223 from joolfe/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
joolfe authored Sep 18, 2022
2 parents 64a7dc7 + 8799631 commit 2edcbbd
Show file tree
Hide file tree
Showing 14 changed files with 753 additions and 194 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
## [2.7.0](https://github.com/joolfe/postman-to-openapi/compare/2.6.2...2.7.0) (2022-09-18)


### Features

* disabled but duplicating params (not supported by OpenAPI) ([4310197](https://github.com/joolfe/postman-to-openapi/commit/4310197386afcdd61aa2d640fa7935eda6f44f41))
* transform disabled option WIP ([b4858a2](https://github.com/joolfe/postman-to-openapi/commit/b4858a2d82beefe72f41d5debf95028711bb041d))


### Bug Fixes

* incorrect conflict in previous merge ([9face89](https://github.com/joolfe/postman-to-openapi/commit/9face89b85d5a77f07743c7ab3355077c300a40e))


### Documentation

* update docs about new feature ([d6c1141](https://github.com/joolfe/postman-to-openapi/commit/d6c1141970ac902304f83d116d95c5923635cee0))
* update typescript definition ([253dec7](https://github.com/joolfe/postman-to-openapi/commit/253dec7bb470a14dc1af6fb323aaae92d6b103c6))
* updates and links ([5e92c6d](https://github.com/joolfe/postman-to-openapi/commit/5e92c6d83cb61a6d628eb844bb649eafc189c41b))

### [2.6.2](https://github.com/joolfe/postman-to-openapi/compare/2.6.1...2.6.2) (2022-09-17)


Expand Down
34 changes: 23 additions & 11 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ The third parameter used in the library method is an `options` object containing
|------------------|------------------------------------------------------------------------------------|
| [info](#info-object) | Basic API information |
| [defaultTag](#defaulttag-string) | Values of the default tag object. |
| [pathDepth](#pathdepth-number) | Number of subpaths that should be part of the operation path. |
| [pathDepth](#pathdepth-number) | Number of sub-paths that should be part of the operation path. |
| [auth](#auth-object) | Global authorization definition object. |
| [servers](#servers-array) | Server list for the OpenApi specs. |
| [externalDocs](#externaldocs-object) | Info about the API external documentation. |
Expand All @@ -144,8 +144,8 @@ The basic information of the API is obtained from Postman collection as describe
| `version` | String. The version of the OpenAPI document. |
| `description` | String. A short description of the API. |
| `termsOfService` | String. A URL to the Terms of Service for the API. MUST be in the format of a URL. |
| `contact` | Object. The contact information for the exposed API. See details in [License and Contact configuration](#license-and-contact-configuration) section. |
| `license` | Object. The license information for the exposed API.See details in [License and Contact configuration](#license-and-contact-configuration) section. |
| `contact` | Object. The contact information for the exposed API. See details in [Pass data as postman collection variables](#pass-data-as-postman-collection-variables) section. |
| `license` | Object. The license information for the exposed API.See details in [Pass data as postman collection variables](#pass-data-as-postman-collection-variables) section. |
| `xLogo` | Object. Contain the info for the `x-logo` extension defined by [redoc](https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-logo) |

Basically this are the required and relevant parameters defined in OpenAPI spec [info object](http://spec.openapis.org/oas/v3.0.3.html#info-object), an example of the option will be:
Expand Down Expand Up @@ -253,7 +253,7 @@ The info about the API external documentation, as described in OpenAPI spec [Ext
}
```

This info can be provided as collection variables in the same way as described in section [License and Contact configuration](#license-and-contact-configuration), you can setup the variables `externalDocs.url` and `externalDocs.description` for provide the information.
This info can be provided as collection variables in the same way as described in section [Pass data as postman collection variables](#pass-data-as-postman-collection-variables), you can setup the variables `externalDocs.url` and `externalDocs.description` for provide the information.

### folders (Object)

Expand Down Expand Up @@ -349,10 +349,20 @@ Take into account that variable values provided in the `additionalVars` Object s

### outputFormat (string)

Indicates the resulting format of the OpenAPI document between `json` and `yaml`, the resulting file will be writte using this format and also the result value fo the method `postmanToOpenApi(...)` will use this format.
Indicates the resulting format of the OpenAPI document between `json` and `yaml`, the resulting file will be write using this format and also the result value fo the method `postmanToOpenApi(...)` will use this format.

Default value is `yaml`, if you use a unknown value `yaml` will be used.

### disabledParams (object)

By default all parameters in the postman collection that has the field `"disabled": true` are ignored and not included in the resulting OpenAPI doc, you can customize this behavior with this options
| Param | Description |
|------------------|------------------------------------------------------------------------------------|
| `includeQuery` | Boolean. Indicates if the "query" parameters disabled should be included into the OpenAPI spec. |
| `includeHeader` | Boolean. Indicates if the "header" parameters disabled should be included into the OpenAPI spec. |

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.

# Features

## Basic conversion
Expand All @@ -367,9 +377,9 @@ For fill the OpenAPI [info object](http://spec.openapis.org/oas/v3.0.3.html#info

Postman don't have any field at collection level that feat with OpenAPI "version" field (is a required field in OpenAPI specification), so this library look for a variable with name `version` in Postman [collection variables](https://learning.postman.com/docs/sending-requests/variables/#defining-collection-variables) or if variable is not defined then will use the default value `1.0.0`.

You can customize all this information with the [Info option](#info-(object)).
You can customize all this information with the [Info option](#info-object).

For info about how to setup the `contact` and `license` properties have a look to section [License and Contact configuration](#license-and-contact-configuration).
For info about how to setup the `contact` and `license` properties have a look to section [Pass data as postman collection variables](#pass-data-as-postman-collection-variables).

Have a look to the [SimplePost collection](https://github.com/joolfe/postman-to-openapi/blob/master/test/v21/SimplePost.json) file for an example of how to use this feature.

Expand All @@ -395,13 +405,15 @@ For headers and query fields you can indicate that this parameter is mandatory/r

Have a look to the [GetMethods collection](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/GetMethods.json), [Headers collection](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/Headers.json) and [PathParams collection](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/PathParams.json) files for examples of how to use this features.

> **Note about duplications:** In Postman is possible to define multiples parameters with the same name/key in Query and Headers sections but in OpenAPI spec the combination of "name" and location (expressed by field "in") in parameters should be unique, to avoid generate invalid OpenAPI spec files the library will only use the first apparition of the parameters and discard the repeated ones, so take into consideration when you define your postman collection.
## Postman authorization

The OpenAPI root [security](http://spec.openapis.org/oas/v3.0.3.html#openapi-object) definition is filled using the authorization method defined at Postman Collection [authorization config](https://learning.postman.com/docs/sending-requests/authorization/#inheriting-auth).

Only types 'Basic Auth' and 'Bearer Token' are supported by now. If you define an authorization at postman request level this will overwrite the global defined for this OpenAPI operation.

You can customize the global authorization definition using the [Auth option](#auth-(object)).
You can customize the global authorization definition using the [Auth option](#auth-object).

Have a look to the collections [AuthBasic](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/AuthBasic.json), [AuthBearer](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/AuthBearer.json) and [AuthMultiple](https://github.com/joolfe/postman-to-openapi/blob/master/test/resources/input/v21/AuthMultiple.json) for examples of how to use this feature.

Expand All @@ -427,7 +439,7 @@ Is as easy as define the values in the "Edit Collection" form page inside the ta

The variables names will be in dot notation, for example for `contact` fields will be as `contact.name`, `contact.url`... Take into account that fields that are required by OpenAPI specs, as `contact.name`, if not provided then all the section will be ignored.

You can also customize this information using the [Info option](#info-(object)), note that info provided by options will overwrite the variables inside the Postman collection (has more priority) but values will be merged from both sources (postman variables and options).
You can also customize this information using the [Info option](#info-object), note that info provided by options will overwrite the variables inside the Postman collection (has more priority) but values will be merged from both sources (postman variables and options).

## Pass Meta-information as markdown

Expand Down Expand Up @@ -488,9 +500,9 @@ A "form-data" request body will be describe as a `multipart/form-data` content w

## Postman raw body

When using the `raw` mode in Postman a select box appear to choose the language, please ensure that you select a language manually, even if you see that select box have "Text" as default in some verison of postman if you choose one manually this will be saved as empty.
When using the `raw` mode in Postman a select box appear to choose the language, please ensure that you select a language manually, even if you see that select box have "Text" as default in some version of postman if you choose one manually this will be saved as empty.

The default behaviour of the library when no language is choosed in the `raw` body type is to use the content type `*/*` with schema type `string`.
The default behavior of the library when no language is selected in the `raw` body type is to use the content type `*/*` with schema type `string`.

</div></div>
<div class="tilted-section"><div markdown="1">
Expand Down
60 changes: 34 additions & 26 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const jsonc = require('jsonc-parser')
async function postmanToOpenApi (input, output, {
info = {}, defaultTag = 'default', pathDepth = 0,
auth: optsAuth, servers, externalDocs = {}, folders = {},
responseHeaders = true, replaceVars = false, additionalVars = {}, outputFormat = 'yaml'
responseHeaders = true, replaceVars = false, additionalVars = {}, outputFormat = 'yaml',
disabledParams = { includeQuery: false, includeHeader: false }
} = {}) {
// TODO validate?
let collectionFile = await resolveInput(input)
Expand All @@ -35,7 +36,7 @@ async function postmanToOpenApi (input, output, {
// Empty folders will have tagged empty
element = (tagged.length > 0) ? tagged.shift() : items[i]
}
// If there are an empty folder at the end of the colection elements could be `undefined`
// If there are an empty folder at the end of the collection elements could be `undefined`
if (element != null) {
const {
request: { url, method, body, description: rawDesc, header = [], auth },
Expand All @@ -53,7 +54,7 @@ async function postmanToOpenApi (input, output, {
...(description ? { description } : {}),
...parseBody(body, method),
...parseOperationAuth(auth, securitySchemes, optsAuth),
...parseParameters(query, header, joinedPath, paramsMeta, pathVars),
...parseParameters(query, header, joinedPath, paramsMeta, pathVars, disabledParams),
...parseResponse(response, events, responseHeaders)
}
}
Expand Down Expand Up @@ -230,30 +231,47 @@ function mapFormData () {
}
}

/**
* Default logic to insert parameters, if parameter exist will not be inserted again.
* In Postman this means that only the first parameter is used, the repeated ones are discarded.
* This is a separated method to allow make it configurable in the future
* @param {Map} parameterMap
* @param {Object} param
* @returns the modified parameterMap
*/
const defaultParamInserter = (parameterMap, param) => {
if (!parameterMap.has(param.name)) {
parameterMap.set(param.name, param)
}
return parameterMap
}

/* Parse the Postman query and header and transform into OpenApi parameters */
function parseParameters (query, header, paths, paramsMeta = {}, pathVars) {
function parseParameters (query, header, paths, paramsMeta = {}, pathVars,
{ includeQuery = false, includeHeader = false }, paramInserter = defaultParamInserter) {
// parse Headers
let parameters = header.reduce(mapParameters('header'), [])
const parameters = [...header.reduce(mapParameters('header', includeHeader, paramInserter), new Map()).values()]
// parse Query
parameters = query.reduce(mapParameters('query'), parameters)
parameters.push(...query.reduce(mapParameters('query', includeQuery, paramInserter), new Map()).values())
// Path params
parameters.push(...extractPathParameters(paths, paramsMeta, pathVars))
return (parameters.length) ? { parameters } : {}
}

/* Accumulator function for different types of parameters */
function mapParameters (type) {
return (parameters, { key, description, value }) => {
function mapParameters (type, includeDisabled, paramInserter) {
return (parameterMap, { key, description, value, disabled }) => {
if (!includeDisabled && disabled === true) return parameterMap
const required = /\[required\]/gi.test(description)
parameters.push({
paramInserter(parameterMap, {
name: key,
in: type,
schema: { type: inferType(value) },
...(required ? { required } : {}),
...(description ? { description: description.replace(/ ?\[required\] ?/gi, '') } : {}),
...(value ? { example: value } : {})
})
return parameters
return parameterMap
}
}

Expand Down Expand Up @@ -404,27 +422,17 @@ function scrapeURL (url) {
}

/**
* Calculate query parameters as postman collection
* Calculate query parameters in postman collection
* @param {*} searchParams The searchParam instance from an URL object
* @param {*} queryCollection The postman collection query section
* @returns A query params array as created by postman collections Array(Obj)
*
* NOTE: This method was created because we think that some versions of postman don´t add the `query`
* parameter in the url, but after some reasearch the reason why the `query` parameter can not be
* present is just because no query parameters are used so we just format the postman `query` array here.
*/
function compoundQueryParams (searchParams, queryCollection = []) {
// Prepare desc in query collection for easy search
const descMap = queryCollection.reduce((agr, { key, description }) => {
agr[key] = description
return agr
}, {})
// Create the query array of objects
const query = []
searchParams.forEach((value, key) => {
query.push({
key,
value,
...(descMap[key] != null ? { description: descMap[key] } : {})
})
})
return query
return queryCollection
}

/* Parse domains from operations or options */
Expand Down
Loading

0 comments on commit 2edcbbd

Please sign in to comment.