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

Commit

Permalink
feat: replace variables from postman collection or new option
Browse files Browse the repository at this point in the history
  • Loading branch information
joolfe committed Aug 1, 2021
1 parent 421a1f9 commit 75f8df1
Show file tree
Hide file tree
Showing 13 changed files with 1,069 additions and 47 deletions.
67 changes: 50 additions & 17 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ const { promises: { writeFile, readFile } } = require('fs')
const { dump } = require('js-yaml')
const { parseMdTable } = require('./md-utils')
const { version } = require('../package.json')
const replacePostmanVariables = require('./var-replacer')

async function postmanToOpenApi (input, output, {
info = {}, defaultTag = 'default', pathDepth = 0,
auth: optsAuth, servers, externalDocs = {}, folders = {},
responseHeaders = true
responseHeaders = true, replaceVars = false, additionalVars = {}
} = {}) {
// TODO validate?
const collectionFile = await readFile(input)
let collectionFile = await readFile(input, 'utf8')
if (replaceVars) {
collectionFile = replacePostmanVariables(collectionFile, additionalVars)
}
const postmanJson = JSON.parse(collectionFile)
const { item: items, variable = [] } = postmanJson
const paths = {}
Expand Down Expand Up @@ -203,7 +207,7 @@ function mapFormData () {
}

/* Parse the Postman query and header and transform into OpenApi parameters */
function parseParameters (query = [], header, paths, paramsMeta = {}) {
function parseParameters (query, header, paths, paramsMeta = {}) {
// parse Headers
let parameters = header.reduce(mapParameters('header'), [])
// parse Query
Expand Down Expand Up @@ -326,7 +330,7 @@ function parseOptsAuth (optAuth) {
}

/* From the path array compose the real path for OpenApi specs */
function calculatePath (paths = [], pathDepth) {
function calculatePath (paths, pathDepth) {
paths = paths.slice(pathDepth) // path depth
// replace repeated '{' and '}' chars
return '/' + paths.map(path => path.replace(/([{}])\1+/g, '$1'))
Expand All @@ -337,24 +341,53 @@ function calculateDomains (protocol, hosts, port) {
return protocol + '://' + hosts.join('.') + (port ? `:${port}` : '')
}

/** Support for collection V2 */
/**
* To support postman collection v2 and variable replace we should parse the `url` or `url.raw` data
* without trust in the object as in v2 could not exist and if replaceVars = true then values cannot
* be correctly parsed
* @param {Object | String} url
* @returns a url structure as in postman v2.1 collections
*/
function scrapeURL (url) {
// Avoid parse empty url request
if (url === '' || url.raw === '') {
return { valid: false }
}
if (typeof url === 'string' || url instanceof String) {
const objUrl = new URL(url)
return {
raw: url,
path: decodeURIComponent(objUrl.pathname).slice(1).split('/'),
query: [],
protocol: objUrl.protocol.slice(0, -1),
host: decodeURIComponent(objUrl.hostname).split('.'),
port: objUrl.port,
valid: true
}
const rawUrl = (typeof url === 'string' || url instanceof String) ? url : url.raw
const objUrl = new URL(rawUrl)
return {
raw: rawUrl,
path: decodeURIComponent(objUrl.pathname).slice(1).split('/'),
query: compoundQueryParams(objUrl.searchParams, url.query),
protocol: objUrl.protocol.slice(0, -1),
host: decodeURIComponent(objUrl.hostname).split('.'),
port: objUrl.port,
valid: true
}
return { ...url, valid: true }
}

/**
* Calculate query parameters as 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)
*/
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
}

/* Parse domains from operations or options */
Expand Down
6 changes: 4 additions & 2 deletions lib/var-replacer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ Mustache.Writer.prototype.escapedValue = function escapedValue (token, context,
return String(value)
}

function replacePostmanVariables (collectionString) {
function replacePostmanVariables (collectionString, additionalVars = {}) {
const postmanJson = JSON.parse(collectionString)
const { variable } = postmanJson
const context = variable.reduce((obj, { key, value }) => {
const formatVars = variable.reduce((obj, { key, value }) => {
obj[key] = value
return obj
}, {})
// Merge collection vars with additional vars
const context = { ...formatVars, ...additionalVars }
return Mustache.render(collectionString, context)
}

Expand Down
19 changes: 19 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const EXPECTED_AUTH_REQUEST = readFileSync('./test/resources/output/AuthRequest.
const EXPECTED_RESPONSES_NO_HEADERS = readFileSync('./test/resources/output/ResponsesNoHeaders.yml', 'utf8')
const EXPECTED_FORM_DATA = readFileSync('./test/resources/output/FormData.yml', 'utf8')
const EXPECTED_FORM_URLENCODED = readFileSync('./test/resources/output/FormUrlencoded.yml', 'utf8')
const EXPECTED_VARIABLES = readFileSync('./test/resources/output/Variables.yml', 'utf8')
const EXPECTED_VARIABLES_ADDITIONAL = readFileSync('./test/resources/output/VariablesAdditional.yml', 'utf8')

const AUTH_DEFINITIONS = {
myCustomAuth: {
Expand Down Expand Up @@ -106,6 +108,7 @@ describe('Library specs', function () {
const COLLECTION_AUTH_REQUEST = `./test/resources/input/${version}/AuthRequest.json`
const COLLECTION_FORM_DATA = `./test/resources/input/${version}/FormData.json`
const COLLECTION_FORM_URLENCODED = `./test/resources/input/${version}/FormUrlencoded.json`
const COLLECTION_VARIABLES = `./test/resources/input/${version}/Variables.json`

it('should work with a basic transform', async function () {
const result = await postmanToOpenApi(COLLECTION_BASIC, OUTPUT_PATH, {})
Expand Down Expand Up @@ -409,6 +412,22 @@ describe('Library specs', function () {
const result = await postmanToOpenApi(COLLECTION_FORM_URLENCODED, OUTPUT_PATH, {})
equal(result, EXPECTED_FORM_URLENCODED)
})

it('should replace postman variables if feature activated', async function () {
const result = await postmanToOpenApi(COLLECTION_VARIABLES, OUTPUT_PATH, { replaceVars: true })
equal(result, EXPECTED_VARIABLES)
})

it('should use additional variables for replace', async function () {
const result = await postmanToOpenApi(COLLECTION_VARIABLES, OUTPUT_PATH, {
replaceVars: true,
additionalVars: {
company: 'myCompany',
service: 'myService'
}
})
equal(result, EXPECTED_VARIABLES_ADDITIONAL)
})
})
})

Expand Down
178 changes: 178 additions & 0 deletions test/resources/input/v2/Variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
{
"info": {
"_postman_id": "747abd37-e913-4bf8-a7e7-01730737b973",
"name": "Variables",
"description": "Mi super test collection from postman",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
},
"item": [
{
"name": "Create new User",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"example\": \"field\",\n \"other\": {\n \"data1\": \"yes\",\n \"service\": \"{{service}}\"\n }\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": "{{server}}/users",
"description": "Create a new user into your amazing API"
},
"response": []
},
{
"name": "Create Post",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "company",
"value": "{{company}}",
"type": "text"
},
{
"key": "text",
"value": "This is an example text",
"type": "text"
},
{
"key": "auditor",
"value": "{{auditor}}",
"type": "text"
}
],
"options": {
"raw": {
"language": "json"
}
}
},
"url": "https://api.io/{{dinamic_path}}/post"
},
"response": []
},
{
"name": "Consult User data",
"request": {
"method": "GET",
"header": [
{
"key": "X-Company",
"value": "{{company}}",
"type": "text"
}
],
"url": {
"raw": "{{server}}/users/{{user_id}}?company={{company}}",
"host": [
"{{server}}"
],
"path": [
"users",
"{{user_id}}"
],
"query": [
{
"key": "company",
"value": "{{company}}"
}
]
},
"description": "Get one user instance data"
},
"response": []
},
{
"name": "Get a list of user",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{server}}/users?size={{page-size}}&company={{company}}",
"host": [
"{{server}}"
],
"path": [
"users"
],
"query": [
{
"key": "size",
"value": "{{page-size}}",
"description": "{{desc-size}}"
},
{
"key": "company",
"value": "{{company}}",
"description": "company for filter users"
}
]
},
"description": "Get a list of users"
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "version",
"value": "1.1.0"
},
{
"key": "server",
"value": "https://api.io"
},
{
"key": "page-size",
"value": "10"
},
{
"key": "company",
"value": "ServicesLTD"
},
{
"key": "auditor",
"value": "IHA"
},
{
"key": "service",
"value": "s23434"
},
{
"key": "desc-size",
"value": "size of the list"
},
{
"key": "dinamic_path",
"value": "test/path/here"
}
]
}
23 changes: 14 additions & 9 deletions test/resources/input/v21/Variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,14 @@
}
},
"url": {
"raw": "{{server}}/post",
"raw": "https://api.io/{{dinamic_path}}/post",
"protocol": "https",
"host": [
"{{server}}"
"api",
"io"
],
"path": [
"{{dinamic_path}}",
"post"
]
}
Expand All @@ -84,12 +87,6 @@
"key": "X-Company",
"value": "{{company}}",
"type": "text"
},
{
"key": "",
"value": "",
"type": "text",
"disabled": true
}
],
"url": {
Expand Down Expand Up @@ -129,7 +126,7 @@
{
"key": "size",
"value": "{{page-size}}",
"description": "size of the list"
"description": "{{desc-size}}"
},
{
"key": "company",
Expand Down Expand Up @@ -187,6 +184,14 @@
{
"key": "service",
"value": "s23434"
},
{
"key": "desc-size",
"value": "size of the list"
},
{
"key": "dinamic_path",
"value": "test/path/here"
}
]
}
Loading

0 comments on commit 75f8df1

Please sign in to comment.