Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

openapi-snippet

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-snippet - npm Package Compare versions

Comparing version 0.11.0 to 0.12.0

test/form_data_example.json

89

index.js

@@ -31,25 +31,23 @@ /**

const har = OpenAPIToHar.getEndpoint(openApi, path, method, values);
const hars = OpenAPIToHar.getEndpoint(openApi, path, method, values);
const snippet = new HTTPSnippet(har);
const snippets = [];
for (let j in targets) {
const target = formatTarget(targets[j]);
if (!target) throw new Error('Invalid target: ' + targets[j]);
snippets.push({
id: targets[j],
title: target.title,
content: snippet.convert(
target.language,
typeof target.library !== 'undefined' ? target.library : null
),
});
for (const har of hars) {
const snippet = new HTTPSnippet(har);
snippets.push(
...getSnippetsForTargets(
targets,
snippet,
har.comment ? har.comment : undefined
)
);
}
// use first element since method, url, and description
// are the same for all elements
return {
method: har.method,
url: har.url,
description: har.description,
resource: getResourceName(har.url),
method: hars[0].method,
url: hars[0].url,
description: hars[0].description,
resource: getResourceName(hars[0].url),
snippets: snippets,

@@ -67,29 +65,19 @@ };

const getSnippets = function (openApi, targets) {
const harList = OpenAPIToHar.getAll(openApi);
const endpointHarInfoList = OpenAPIToHar.getAll(openApi);
const results = [];
for (let i in harList) {
for (let i in endpointHarInfoList) {
// create HTTPSnippet object:
const har = harList[i];
const snippet = new HTTPSnippet(har.har);
const harInfo = endpointHarInfoList[i];
const snippets = [];
for (let j in targets) {
const target = formatTarget(targets[j]);
if (!target) throw new Error('Invalid target: ' + targets[j]);
snippets.push({
id: targets[j],
title: target.title,
content: snippet.convert(
target.language,
typeof target.library !== 'undefined' ? target.library : null
),
});
for (const har of harInfo.hars) {
const snippet = new HTTPSnippet(har);
snippets.push(...getSnippetsForTargets(targets, snippet, har.comment));
}
results.push({
method: har.method,
url: har.url,
description: har.description,
resource: getResourceName(har.url),
method: harInfo.method,
url: harInfo.url,
description: harInfo.description,
resource: getResourceName(harInfo.url),
snippets,

@@ -200,2 +188,27 @@ });

/**
* Generate code snippets for each of the supplied targets
*
* @param targets {array} List of language targets to generate code for
* @param snippet {Object} Snippet object from httpsnippet to convert into the target objects
* @param mimeType {string | undefined} Additional information to add uniqueness to the produced snippets
*/
const getSnippetsForTargets = function (targets, snippet, mimeType) {
const snippets = [];
for (let j in targets) {
const target = formatTarget(targets[j]);
if (!target) throw new Error('Invalid target: ' + targets[j]);
snippets.push({
id: targets[j],
...(mimeType !== undefined && { mimeType: mimeType }),
title: target.title,
content: snippet.convert(
target.language,
typeof target.library !== 'undefined' ? target.library : null
),
});
}
return snippets;
};
const capitalizeFirstLetter = function (string) {

@@ -202,0 +215,0 @@ return string.charAt(0).toUpperCase() + string.slice(1);

@@ -31,3 +31,3 @@ /**

* @param {Object} queryParamValues Optional: Values for the query parameters if present
* @return {Object} HAR Request object
* @return {array} List of HAR Request objects for the endpoint
*/

@@ -42,3 +42,3 @@ const createHar = function (openApi, path, method, queryParamValues) {

const har = {
const baseHar = {
method: method.toUpperCase(),

@@ -54,7 +54,25 @@ url: baseUrl + getFullPath(openApi, path, method),

let hars = [];
// get payload data, if available:
const postData = getPayload(openApi, path, method);
if (postData) har.postData = postData;
const postDatas = getPayloads(openApi, path, method);
return har;
// For each postData create a snippet
if (postDatas.length > 0) {
for (let i in postDatas) {
const postData = postDatas[i];
const copiedHar = JSON.parse(JSON.stringify(baseHar));
copiedHar.postData = postData;
copiedHar.comment = postData.mimeType;
copiedHar.headers.push({
name: 'content-type',
value: postData.mimeType,
});
hars.push(copiedHar);
}
} else {
hars = [baseHar];
}
return hars;
};

@@ -70,5 +88,5 @@

* @param {string} method
* @return {object}
* @return {array} A list of payload objects
*/
const getPayload = function (openApi, path, method) {
const getPayloads = function (openApi, path, method) {
if (typeof openApi.paths[path][method].parameters !== 'undefined') {

@@ -88,6 +106,8 @@ for (let i in openApi.paths[path][method].parameters) {

);
return {
mimeType: 'application/json',
text: JSON.stringify(sample),
};
return [
{
mimeType: 'application/json',
text: JSON.stringify(sample),
},
];
} catch (err) {

@@ -111,2 +131,3 @@ console.log(err);

const payloads = [];
if (

@@ -116,55 +137,53 @@ openApi.paths[path][method].requestBody &&

) {
if (
openApi.paths[path][method].requestBody.content['application/json'] &&
openApi.paths[path][method].requestBody.content['application/json'].schema
) {
const sample = OpenAPISampler.sample(
openApi.paths[path][method].requestBody.content['application/json']
.schema,
{ skipReadOnly: true },
openApi
);
return {
mimeType: 'application/json',
text: JSON.stringify(sample),
};
}
[
'application/json',
'application/x-www-form-urlencoded',
'multipart/form-data',
].forEach((type) => {
const content = openApi.paths[path][method].requestBody.content[type];
if (content && content.schema) {
const sample = OpenAPISampler.sample(
content.schema,
{ skipReadOnly: true },
openApi
);
if (type === 'application/json') {
payloads.push({
mimeType: type,
text: JSON.stringify(sample),
});
} else if (type === 'multipart/form-data') {
if (sample !== undefined) {
const params = Object.keys(sample).reduce(
(acc, key) => acc.concat([{ name: key, value: sample[key] }]),
[]
);
payloads.push({
mimeType: type,
params: params,
});
}
} else if (type == 'application/x-www-form-urlencoded') {
if (sample === undefined) return null;
if (
openApi.paths[path][method].requestBody.content[
'application/x-www-form-urlencoded'
] &&
openApi.paths[path][method].requestBody.content[
'application/x-www-form-urlencoded'
].schema
) {
const sample = OpenAPISampler.sample(
openApi.paths[path][method].requestBody.content[
'application/x-www-form-urlencoded'
].schema,
{ skipReadOnly: true },
openApi
);
const params = [];
Object.keys(sample).map((key) =>
params.push({
name: encodeURIComponent(key).replace(/\%20/g, '+'),
value: encodeURIComponent(sample[key]).replace(/\%20/g, '+'),
})
);
if (sample === undefined) return null;
const params = [];
Object.keys(sample).map((key) =>
params.push({
name: encodeURIComponent(key).replace(/\%20/g, '+'),
value: encodeURIComponent(sample[key]).replace(/\%20/g, '+'),
})
);
return {
mimeType: 'application/x-www-form-urlencoded',
params: params,
text: Object.keys(params)
.map((key) => key + '=' + sample[key])
.join('&'),
};
}
payloads.push({
mimeType: 'application/x-www-form-urlencoded',
params: params,
text: Object.keys(params)
.map((key) => key + '=' + sample[key])
.join('&'),
});
}
}
});
}
return null;
return payloads;
};

@@ -202,5 +221,5 @@

* Gets an object describing the the paremeters (header or query) in a given OpenAPI method
* @param {Object} param parameter values to use in snippet
* @param {Object} values Optional: query parameter values to use in the snippet if present
* @returns {Object} Object describing the parameters in a given OpenAPI method
* @param {Object} param parameter values to use in snippet
* @param {Object} values Optional: query parameter values to use in the snippet if present
* @return {Object} Object describing the parameters in a given OpenAPI method or path
*/

@@ -230,2 +249,40 @@ const getParameterValues = function (param, values) {

/**
* Parse parameter object into query string objects
*
* @param {Object} openApi OpenApi document
* @param {Object} parameters Objects described in the document to parse into the query string
* @param {Object} values Optional: query parameter values to use in the snippet if present
* @return {Object} Object describing the parameters for a method or path
*/
const parseParametersToQuery = function (openApi, parameters, values) {
const queryStrings = {};
for (let i in parameters) {
let param = parameters[i];
if (typeof param['$ref'] === 'string' && /^#/.test(param['$ref'])) {
param = resolveRef(openApi, param['$ref']);
}
if (typeof param.schema !== 'undefined') {
if (
typeof param.schema['$ref'] === 'string' &&
/^#/.test(param.schema['$ref'])
) {
param.schema = resolveRef(openApi, param.schema['$ref']);
if (typeof param.schema.type === 'undefined') {
// many schemas don't have an explicit type
param.schema.type = 'object';
}
}
}
if (typeof param.in !== 'undefined' && param.in.toLowerCase() === 'query') {
// param.name is a safe key, because the spec defines
// that name MUST be unique
queryStrings[param.name] = getParameterValues(param, values);
}
}
return queryStrings;
};
/**
* Get array of objects describing the query parameters for a path and method

@@ -246,32 +303,29 @@ * pair described in the given OpenAPI document.

const queryStrings = [];
let pathQueryStrings = {};
let methodQueryStrings = {};
// First get any parameters from the path
if (typeof openApi.paths[path].parameters !== 'undefined') {
pathQueryStrings = parseParametersToQuery(
openApi,
openApi.paths[path].parameters,
values
);
}
if (typeof openApi.paths[path][method].parameters !== 'undefined') {
for (let i in openApi.paths[path][method].parameters) {
let param = openApi.paths[path][method].parameters[i];
if (typeof param['$ref'] === 'string' && /^#/.test(param['$ref'])) {
param = resolveRef(openApi, param['$ref']);
}
if (typeof param.schema !== 'undefined') {
if (
typeof param.schema['$ref'] === 'string' &&
/^#/.test(param.schema['$ref'])
) {
param.schema = resolveRef(openApi, param.schema['$ref']);
if (typeof param.schema.type === 'undefined') {
// many schemas don't have an explicit type
param.schema.type = 'object';
}
}
}
if (
typeof param.in !== 'undefined' &&
param.in.toLowerCase() === 'query'
) {
queryStrings.push(getParameterValues(param, values));
}
}
methodQueryStrings = parseParametersToQuery(
openApi,
openApi.paths[path][method].parameters,
values
);
}
return queryStrings;
// Merge query strings, with method overriding path
// from the spec:
// If a parameter is already defined at the Path Item, the new definition will override
// it but can never remove it.
// https://swagger.io/specification/
const queryStrings = Object.assign(pathQueryStrings, methodQueryStrings);
return Object.values(queryStrings);
};

@@ -336,23 +390,2 @@

// 'content-type' header:
if (typeof pathObj.produces !== 'undefined') {
for (let j in pathObj.produces) {
const type2 = pathObj.produces[j];
headers.push({
name: 'content-type',
value: type2,
});
}
}
// v3 'content-type' header:
if (pathObj.requestBody && pathObj.requestBody.content) {
for (const type3 of Object.keys(pathObj.requestBody.content)) {
headers.push({
name: 'content-type',
value: type3,
});
}
}
// headers defined in path object:

@@ -483,3 +516,4 @@ if (typeof pathObj.parameters !== 'undefined') {

const url = getBaseUrl(openApi, path, method) + path;
const har = createHar(openApi, path, method);
const hars = createHar(openApi, path, method);
// need to push multiple here
harList.push({

@@ -491,3 +525,3 @@ method: method.toUpperCase(),

'No description available',
har: har,
hars: hars,
});

@@ -494,0 +528,0 @@ }

{
"name": "openapi-snippet",
"version": "0.11.0",
"version": "0.12.0",
"description": "Generates code snippets from Open API (previously Swagger) documents.",

@@ -5,0 +5,0 @@ "repository": {

@@ -76,2 +76,3 @@ # OpenAPI Snippet

"id": "node",
"mimeType": "application/json", // Only set for methods with a request body
"title": "Node + Native",

@@ -78,0 +79,0 @@ "content": "var http = require(\"https\");\n\nvar options = {..."

@@ -22,6 +22,3 @@ {

"type": "object",
"required": [
"id",
"secret"
],
"required": ["id", "secret"],
"properties": {

@@ -28,0 +25,0 @@ "id": {

@@ -78,2 +78,112 @@ {

}
},
"/animals": {
"parameters": [
{
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"style": "form",
"example": ["dog", "cat"],
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"example": 10,
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"get": {
"description": "Get Pets from store",
"operationId": "getPet",
"responses": {
"200": {
"description": "pet response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pet"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/species": {
"parameters": [
{
"name": "id",
"in": "query",
"description": "the species id",
"required": false,
"example": 1,
"schema": {
"type": "integer"
}
}
],
"get": {
"description": "Get Pets from store",
"operationId": "getPet",
"parameters": [
{
"name": "id",
"in": "query",
"description": "A comma-seperated list of species IDs",
"required": false,
"example": [1, 2],
"schema": {
"type": "array",
"items": {
"type": "integer"
}
}
}
],
"responses": {
"200": {
"description": "pet response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Species"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}

@@ -110,2 +220,16 @@ },

},
"Species": {
"items": {
"$ref": "#/components/thing"
},
"type": "array"
},
"Thing": {
"required": ["id"],
"properties": {
"id": {
"type": "integer"
}
}
},
"Error": {

@@ -112,0 +236,0 @@ "required": ["code", "message"],

@@ -15,3 +15,5 @@ 'use strict';

const ParameterExampleReferenceAPI = require('./parameter_example_swagger.json');
const FormDataExampleReferenceAPI = require('./form_data_example.json');
const FormUrlencodedExampleAPI = require('./form_urlencoded_example.json');
const MultipleRequestContentReferenceAPI = require('./multiple_request_content.json');

@@ -202,2 +204,84 @@ test('Getting snippets should not result in error or undefined', function (t) {

test('Generate snippet with multipart/form-data', function (t) {
const result = OpenAPISnippets.getEndpointSnippets(
FormDataExampleReferenceAPI,
'/pets',
'patch',
['node_request']
);
const snippet = result.snippets[0].content;
t.true(/boundary=---011000010111000001101001/.test(snippet));
t.true(
/formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string'}/.test(snippet)
);
t.end();
});
test('Generate snippets with multiple content types', function (t) {
const result = OpenAPISnippets.getEndpointSnippets(
MultipleRequestContentReferenceAPI,
'/pets',
'patch',
['node_request']
);
t.equal(result.snippets.length, 2);
for (const snippet of result.snippets) {
if (snippet.mimeType === 'application/json') {
t.true(
/headers: {'content-type': 'application\/json'}/.test(snippet.content)
);
t.true(/body: {name: 'string', tag: 'string'}/.test(snippet.content));
} else if (snippet.mimeType === 'multipart/form-data') {
t.true(
/headers: {'content-type': 'multipart\/form-data; boundary=---011000010111000001101001'}/.test(
snippet.content
)
);
t.true(
/formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string', 'pet\[picture\]': 'string'}/.test(
snippet.content
)
);
}
}
t.end();
});
test('Query Params Defined for all methods should be resolved', function (t) {
const result = OpenAPISnippets.getEndpointSnippets(
ParameterExampleReferenceAPI,
'/animals',
'get',
['node_request']
);
const snippet = result.snippets[0].content;
t.true(/ {tags: 'dog,cat', limit: '10'}/.test(snippet));
t.false(/SOME_INTEGER_VALUE/.test(snippet));
t.end();
});
test('Query Params Defined for all methods are overriden by method definitions', function (t) {
const result = OpenAPISnippets.getEndpointSnippets(
ParameterExampleReferenceAPI,
'/species',
'get',
['node_request']
);
const snippet = result.snippets[0].content;
t.true(/ qs: {id: '1,2'}/.test(snippet));
t.end();
});
test('Snippet for Get with no parameters should work', function (t) {
const result = OpenAPISnippets.getEndpointSnippets(
InstagramOpenAPI,
'/media/popular',
'get',
['node_request']
);
const snippet = result.snippets[0].content;
t.false(/qs/.test(snippet));
t.end();
});
test('Testing the application/x-www-form-urlencoded example case', function (t) {

@@ -204,0 +288,0 @@ t.plan(2);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc