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

Commit

Permalink
feat: Add support for contact and license #35
Browse files Browse the repository at this point in the history
  • Loading branch information
joolfe committed Aug 3, 2020
1 parent 1a59529 commit 40785f4
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 6 deletions.
Binary file removed docs/images/console-log.png
Binary file not shown.
Binary file added docs/images/variables.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 29 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Automatic infer types from query and headers parameters.
- Support Json and Text body formats.
- Global Authorization parse or by configuration (Basic and Bearer).
- Contact and License from variables or by configuration.

See [Features](#features) section for more details about how to use each of this features.

Expand Down Expand Up @@ -87,10 +88,12 @@ The basic information of the API is obtained from Postman collection as describe

| Param | Description |
|------------------|------------------------------------------------------------------------------------|
| `title` | String. The title of the API. |
| `version` | String. The version of the OpenAPI document. |
| `title` | String. The title of the API. |
| `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. |

Basically this are the required and relevant parameters defined in OpenAPI spec [info object](https://swagger.io/specification/#info-object), an example of the option will be:

Expand All @@ -100,7 +103,16 @@ Basically this are the required and relevant parameters defined in OpenAPI spec
title: 'Options title',
version: '6.0.7-beta',
description: 'Description from options',
termsOfService: 'http://tos.myweb.com'
termsOfService: 'http://tos.myweb.com',
license: {
name: 'MIT',
url: 'https://es.wikipedia.org/wiki/Licencia_MIT'
},
contact: {
name: 'My Support',
url: 'http://www.api.com/support',
email: 'support@api.com'
}
}
}
```
Expand Down Expand Up @@ -173,6 +185,8 @@ Postman don't have any field at collection level that feat with OpenAPI "version

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).

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

## Folders as tags
Expand Down Expand Up @@ -213,6 +227,18 @@ const result = await postmanToOpenApi(postmanCollection, outputFile, { servers:

This will remove the `servers` field from the yml specification result.

## License and Contact configuration

Inside the [info object](https://swagger.io/specification/#info-object) of OpenAPI definition exist two Object fields called `contact` and `license`, this fields are very useful for provide information to developers, but inside a Postman collection not exist any "standard" way to save this information, for this reason we use [Postman collection variables](https://learning.postman.com/docs/sending-requests/variables/) to define this options.

Is as easy as define the values in the "Edit Collection" form page inside the tab "Variables", as showed in the next image:

![contact and license variables](images/variables.png)

The variables names will be in dot notation, for example for `contact` fields will be as `contact.name`, `contact.url`... Take into account that some of this fields are required as described in OpenAPI specs if not provided 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).

</div></div>
<div class="tilted-section"><div markdown="1">

Expand Down
34 changes: 31 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,43 @@ async function postmanToOpenApi (input, output, { info = {}, defaultTag = 'defau
function compileInfo (postmanJson, optsInfo) {
const { info: { name, description: desc }, variable = [] } = postmanJson
const ver = getVarValue(variable, 'version', '1.0.0')
const { title = name, description = desc, version = ver, termsOfService } = optsInfo
const {
title = name, description = desc, version = ver,
termsOfService, license, contact
} = optsInfo
return {
title,
description,
version,
...(termsOfService ? { termsOfService } : {})
...(termsOfService ? { termsOfService } : {}),
...parseContact(variable, contact),
...parseLicense(variable, license)
}
}

function parseLicense (variables, optsLicense = {}) {
const nameVar = getVarValue(variables, 'license.name')
const urlVar = getVarValue(variables, 'license.url')
const { name = nameVar, url = urlVar } = optsLicense
return (name != null) ? { license: { name, ...(url ? { url } : {}) } } : {}
}

function parseContact (variables, optsContact = {}) {
const nameVar = getVarValue(variables, 'contact.name')
const urlVar = getVarValue(variables, 'contact.url')
const emailVar = getVarValue(variables, 'contact.email')
const { name = nameVar, url = urlVar, email = emailVar } = optsContact
return [name, url, email].some(e => e != null)
? {
contact: {
...(name ? { name } : {}),
...(url ? { url } : {}),
...(email ? { email } : {})
}
}
: {}
}

function parseBody (body = {}, method) {
// Swagger validation return an error if GET has body
if (['GET'].includes(method)) return {}
Expand Down Expand Up @@ -142,7 +170,7 @@ function extractPathParameters (path) {
}))
}

function getVarValue (variables, name, def) {
function getVarValue (variables, name, def = undefined) {
const variable = variables.find(({ key }) => key === name)
return variable ? variable.value : def
}
Expand Down
26 changes: 26 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const COLLECTION_AUTH_BEARER = './test/resources/input/AuthBearer.json'
const COLLECTION_AUTH_BASIC = './test/resources/input/AuthBasic.json'
const COLLECTION_PATH_PARAMS = './test/resources/input/PathParams.json'
const COLLECTION_MULTIPLE_SERVERS = './test/resources/input/MultipleServers.json'
const COLLECTION_LICENSE_CONTACT = './test/resources/input/LicenseContact.json'

const EXPECTED_BASIC = readFileSync('./test/resources/output/Basic.yml', 'utf8')
const EXPECTED_INFO_OPTS = readFileSync('./test/resources/output/InfoOpts.yml', 'utf8')
Expand All @@ -33,6 +34,8 @@ const EXPECTED_PATH_PARAMS = readFileSync('./test/resources/output/PathParams.ym
const EXPECTED_MULTIPLE_SERVERS = readFileSync('./test/resources/output/MultipleServers.yml', 'utf8')
const EXPECTED_SERVERS_OPTIONS = readFileSync('./test/resources/output/ServersOpts.yml', 'utf8')
const EXPECTED_NO_SERVERS = readFileSync('./test/resources/output/NoServers.yml', 'utf8')
const EXPECTED_LICENSE_CONTACT = readFileSync('./test/resources/output/LicenseContact.yml', 'utf8')
const EXPECTED_LICENSE_CONTACT_OPT = readFileSync('./test/resources/output/LicenseContactOpts.yml', 'utf8')

describe('Library specs', function () {
afterEach('remove file', function () {
Expand Down Expand Up @@ -151,4 +154,27 @@ describe('Library specs', function () {
const result = await postmanToOpenApi(COLLECTION_MULTIPLE_SERVERS, OUTPUT_PATH, { servers: [] })
equal(result, EXPECTED_NO_SERVERS)
})

it('should parse license and contact from variables', async function () {
const result = await postmanToOpenApi(COLLECTION_LICENSE_CONTACT, OUTPUT_PATH)
equal(result, EXPECTED_LICENSE_CONTACT)
})

it('should use license from options', async function () {
const result = await postmanToOpenApi(COLLECTION_LICENSE_CONTACT, OUTPUT_PATH,
{
info: {
license: {
name: 'MIT',
url: 'https://es.wikipedia.org/wiki/Licencia_MIT'
},
contact: {
name: 'My Support',
url: 'http://www.api.com/support',
email: 'support@api.com'
}
}
})
equal(result, EXPECTED_LICENSE_CONTACT_OPT)
})
})
102 changes: 102 additions & 0 deletions test/resources/input/LicenseContact.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{
"info": {
"_postman_id": "9f1fe3cc-9229-471a-96b4-6bca41bd7ab0",
"name": "License and Contact",
"description": "Collection to test license as variable",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Get list of users",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "https://api.io/users?age=45&name=Jhon&review=true&number=23.56",
"protocol": "https",
"host": [
"api",
"io"
],
"path": [
"users"
],
"query": [
{
"key": "age",
"value": "45",
"description": "Filter by age"
},
{
"key": "name",
"value": "Jhon",
"description": "Filter by name"
},
{
"key": "review",
"value": "true",
"description": "Indicate if should be reviewed or not"
},
{
"key": "number",
"value": "23.56",
"description": "This is a number"
}
]
},
"description": "Obtain a list of users that fullfill the conditions of the filters"
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"id": "2973e583-323c-418e-a553-096171309624",
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"id": "c0dc618b-5ca4-43db-8b6e-ac29eff17880",
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"id": "b573c8e4-6a13-4d0e-8c3b-19536462f36c",
"key": "license.name",
"value": "Apache 2.0"
},
{
"id": "b1aecf73-5ff1-4cea-b447-80fe28da62c1",
"key": "license.url",
"value": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
{
"id": "35641083-7bd6-4c98-b2a8-4b45da0cdeb9",
"key": "contact.name",
"value": "API Support"
},
{
"id": "7762d7a2-78f9-46eb-bf99-2a9519f35a79",
"key": "contact.url",
"value": "http://www.example.com/support"
},
{
"id": "77c31f06-45ae-40ef-9734-1b03b7bd21fc",
"key": "contact.email",
"value": "support@example.com"
}
],
"protocolProfileBehavior": {}
}
51 changes: 51 additions & 0 deletions test/resources/output/LicenseContact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
openapi: 3.0.0
info:
title: License and Contact
description: Collection to test license as variable
version: 1.0.0
contact:
name: API Support
url: 'http://www.example.com/support'
email: support@example.com
license:
name: Apache 2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
servers:
- url: 'https://api.io'
paths:
/users:
get:
tags:
- default
summary: Get list of users
description: Obtain a list of users that fullfill the conditions of the filters
parameters:
- name: age
in: query
schema:
type: integer
description: Filter by age
example: '45'
- name: name
in: query
schema:
type: string
description: Filter by name
example: Jhon
- name: review
in: query
schema:
type: boolean
description: Indicate if should be reviewed or not
example: 'true'
- name: number
in: query
schema:
type: number
description: This is a number
example: '23.56'
responses:
'200':
description: Successful response
content:
application/json: {}
51 changes: 51 additions & 0 deletions test/resources/output/LicenseContactOpts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
openapi: 3.0.0
info:
title: License and Contact
description: Collection to test license as variable
version: 1.0.0
contact:
name: My Support
url: 'http://www.api.com/support'
email: support@api.com
license:
name: MIT
url: 'https://es.wikipedia.org/wiki/Licencia_MIT'
servers:
- url: 'https://api.io'
paths:
/users:
get:
tags:
- default
summary: Get list of users
description: Obtain a list of users that fullfill the conditions of the filters
parameters:
- name: age
in: query
schema:
type: integer
description: Filter by age
example: '45'
- name: name
in: query
schema:
type: string
description: Filter by name
example: Jhon
- name: review
in: query
schema:
type: boolean
description: Indicate if should be reviewed or not
example: 'true'
- name: number
in: query
schema:
type: number
description: This is a number
example: '23.56'
responses:
'200':
description: Successful response
content:
application/json: {}

0 comments on commit 40785f4

Please sign in to comment.