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

Commit

Permalink
feat: parse API response from postman examples
Browse files Browse the repository at this point in the history
  • Loading branch information
joolfe committed Jun 11, 2021
1 parent b2ced51 commit b731f4e
Show file tree
Hide file tree
Showing 4 changed files with 768 additions and 3 deletions.
97 changes: 94 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async function postmanToOpenApi (input, output, {
}
const {
request: { url, method, body, description: rawDesc, header, auth },
name: summary, tag = defaultTag, event: events
name: summary, tag = defaultTag, event: events, response
} = element
const { path, query, protocol, host, port, valid } = scrapeURL(url)
if (valid) {
Expand All @@ -45,7 +45,7 @@ async function postmanToOpenApi (input, output, {
...parseBody(body, method),
...parseOperationAuth(auth, securitySchemes, optsAuth),
...parseParameters(query, header, joinedPath, paramsMeta),
responses: parseResponse(events)
...parseResponse(response, events)
}
}
}
Expand Down Expand Up @@ -353,7 +353,15 @@ function descriptionParse (description) {
}
}

function parseResponse (events = []) {
function parseResponse (responses, events) {
if (responses != null) {
return parseResponseFromExamples(responses)
} else {
return { responses: parseResponseFromEvents(events) }
}
}

function parseResponseFromEvents (events = []) {
let status = 200
const test = events.filter(event => event.listen === 'test')
if (test.length > 0) {
Expand All @@ -371,6 +379,89 @@ function parseResponse (events = []) {
}
}

function parseResponseFromExamples (responses) {
// Group responses by status code
const statusCodeMap = responses
.reduce((statusMap, { name, code, status: description, header, body, _postman_previewlanguage: language }) => {
if (code in statusMap) {
if (!(language in statusMap[code].bodies)) {
statusMap[code].bodies[language] = []
}
statusMap[code].bodies[language].push({ name, body })
} else {
statusMap[code] = {
description,
header,
bodies: { [language]: [{ name, body }] }
}
}
return statusMap
}, {})
// Parse for OpenAPI
const parsedResponses = Object.entries(statusCodeMap)
.reduce((parsed, [status, { description, header, bodies }]) => {
parsed[status] = {
description,
...parseResponseHeaders(header),
...parseContent(bodies)
}
return parsed
}, {})
return { responses: parsedResponses }
}

function parseContent (bodiesByLanguage) {
const content = Object.entries(bodiesByLanguage)
.reduce((content, [language, bodies]) => {
if (language === 'json') {
content['application/json'] = {
schema: { type: 'object' },
...parseExamples(bodies, 'json')
}
} else if (language === 'text') {
content['text/plain'] = {
schema: { type: 'string' },
...parseExamples(bodies, 'text')
}
}
return content
}, {})
return { content }
}

// TODO should not fail if body, json is not correct (empty)
// TODO should support string only
function parseExamples (bodies, language) {
if (Array.isArray(bodies) && bodies.length > 1) {
return {
examples: bodies.reduce((ex, { name: summary, body }, i) => {
ex[`example-${i}`] = {
summary,
value: (language === 'json') ? JSON.parse(body) : body
}
return ex
}, {})
}
} else {
return {
example: (language === 'json') ? JSON.parse(bodies[0].body) : bodies[0].body
}
}
}

function parseResponseHeaders (headerArray) {
const headers = headerArray.reduce((acc, { key, value }) => {
acc[key] = {
schema: {
type: inferType(value),
example: value
}
}
return acc
}, {})
return (Object.keys(headers).length > 0) ? { headers } : {}
}

postmanToOpenApi.version = version

module.exports = postmanToOpenApi
8 changes: 8 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ describe('Library specs', function () {
})
})

// TODO add the user id description of the field in markdown or were is need it
it.only('should add responses from postman examples', async function () {
const result = await postmanToOpenApi('./test/resources/input/v21/Responses.json', OUTPUT_PATH, { pathDepth: 2 })
console.log(result)
// equal(result, EXPECTED_BASIC)
})
it('should add responses from multiple format for the same status code (text and json)')

it('should work if no options in request body', async function () {
const result = await postmanToOpenApi(COLLECTION_NO_OPTIONS, OUTPUT_PATH, {})
equal(result, EXPECTED_BASIC)
Expand Down
Loading

0 comments on commit b731f4e

Please sign in to comment.