├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── openapi-to-har.js ├── package-lock.json ├── package.json └── test ├── blogger_swagger.json ├── form_data_example.json ├── form_urlencoded_example.json ├── github_swagger.json ├── ibm_watson_alchemy_data_news_api.json ├── instagram_swagger.json ├── multiple_request_content.json ├── parameter_example_swagger.json ├── parameter_schema_reference.json ├── parameter_variations_swagger.json ├── petstore_oas.json ├── petstore_swagger.json ├── test.js └── watson_alchemy_language_swagger.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # build file: 40 | dist 41 | 42 | .DS_Store -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | *.yml 3 | *.md 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | cache: 5 | directories: 6 | - "node_modules" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Erik Wittern 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenAPI Snippet 2 | **Generates code snippets from Open API (previously Swagger) documents.** 3 | 4 | This package takes as input an OpenAPI v2.0 or v3.0.x document. It translates the document into an [HTTP Archive 1.2 request object](http://www.softwareishard.com/blog/har-12-spec/#request). It uses the [HTTP Snippet](https://github.com/Mashape/httpsnippet) library to generate code snippets for every API endpoint (URL path + HTTP method) defined in the specification in various languages & tools (`cURL`, `Node`, `Python`, `Ruby`, `Java`, `Go`, `C#`...), or for selected endpoints. 5 | 6 | ## Installation 7 | 8 | ```bash 9 | npm i openapi-snippet 10 | ``` 11 | 12 | ## Build OpenAPI Snippet (for use in browser) 13 | Clone this repository. Install required dependencies: 14 | 15 | ```bash 16 | npm i 17 | ``` 18 | 19 | Build a minified version of OpenAPI Snippet (`openapisnippet.min.js`): 20 | 21 | ```bash 22 | npm run build 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### As a module 28 | 29 | ```javascript 30 | const OpenAPISnippet = require('openapi-snippet') 31 | 32 | // define input: 33 | const openApi = ... // Open API document 34 | const targets = ['node_unirest', 'c'] // array of targets for code snippets. See list below... 35 | 36 | try { 37 | // either, get snippets for ALL endpoints: 38 | const results = OpenAPISnippet.getSnippets(openApi, targets) // results is now array of snippets, see "Output" below. 39 | 40 | // ...or, get snippets for a single endpoint: 41 | const results2 = OpenAPISnippet.getEndpointSnippets(openApi, '/users/{user-id}/relationship', 'get', targets) 42 | } catch (err) { 43 | // do something with potential errors... 44 | } 45 | ``` 46 | 47 | ### Within the browser 48 | 49 | Include the `openapisnippet.min.js` file created after building the the library (see above) in your HTML page: 50 | 51 | ```html 52 | 53 | ``` 54 | 55 | Use OpenAPI Snippet, which now defines the global variable `OpenAPISnippet`. 56 | 57 | 58 | ## Output 59 | The output for every endpoint is an object, containing the `method`, `url`, a human-readable `description`, and the corresponding `resource` - all of these values stem from the OpenAPI document. In addition, within the `snippets` list, an object containing a code snippet for every chosen target is provided. As of version `0.4.0`, the snippets include exemplary payload data. 60 | 61 | If `getSnippets` is used, an array of the above described objects is returned. 62 | 63 | For example: 64 | 65 | ```js 66 | [ 67 | // ... 68 | { 69 | "method": "GET", 70 | "url": "https://api.instagram.com/v1/users/{user-id}/relationship", 71 | "description": "Get information about a relationship to another user.", 72 | "resource": "relationship", 73 | "snippets": [ 74 | { 75 | "id": "node", 76 | "mimeType": "application/json", // Only set for methods with a request body 77 | "title": "Node + Native", 78 | "content": "var http = require(\"https\");\n\nvar options = {..." 79 | } 80 | ] 81 | } 82 | // ... 83 | ] 84 | ``` 85 | 86 | ## Targets 87 | Currently, OpenAPI Snippet supports the following [targets](https://github.com/Kong/httpsnippet/tree/master/src/targets) (depending on the HTTP Snippet library): 88 | 89 | * `c_libcurl` (default) 90 | * `csharp_restsharp` (default) 91 | * `csharp_httpclient` 92 | * `go_native` (default) 93 | * `java_okhttp` 94 | * `java_unirest` (default) 95 | * `javascript_jquery` 96 | * `javascript_xhr` (default) 97 | * `node_native` (default) 98 | * `node_request` 99 | * `node_unirest` 100 | * `objc_nsurlsession` (default) 101 | * `ocaml_cohttp` (default) 102 | * `php_curl` (default) 103 | * `php_http1` 104 | * `php_http2` 105 | * `python_python3` (default) 106 | * `python_requests` 107 | * `ruby_native` (default) 108 | * `shell_curl` (default) 109 | * `shell_httpie` 110 | * `shell_wget` 111 | * `swift_nsurlsession` (default) 112 | 113 | If only the language is provided (e.g., `c`), the default library will be selected. 114 | 115 | 116 | License: MIT 117 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * openapi-snippet 3 | * 4 | * Generates code snippets from Open API (previously Swagger) documents. 5 | * 6 | * Author: Erik Wittern 7 | * License: MIT 8 | */ 9 | 'use strict'; 10 | 11 | const OpenAPIToHar = require('./openapi-to-har.js'); 12 | const HTTPSnippet = require('httpsnippet'); 13 | 14 | /** 15 | * Return snippets for endpoint identified using path and method in the given 16 | * OpenAPI document. 17 | * 18 | * @param {object} openApi OpenAPI document 19 | * @param {string} path Path identifying endpoint, e.g., '/users' 20 | * @param {string} method HTTP method identifying endpoint, e.g., 'get' 21 | * @param {array} targets List of languages to create snippets in, e.g, 22 | * ['cURL', 'Node'] 23 | * @param {object} values Optional: Values for the query parameters if present 24 | */ 25 | const getEndpointSnippets = function (openApi, path, method, targets, values) { 26 | // if optional parameter is not provided, set it to empty object 27 | if (typeof values === 'undefined') { 28 | values = {}; 29 | } 30 | 31 | const hars = OpenAPIToHar.getEndpoint(openApi, path, method, values); 32 | 33 | const snippets = []; 34 | for (const har of hars) { 35 | const snippet = new HTTPSnippet(har); 36 | snippets.push( 37 | ...getSnippetsForTargets( 38 | targets, 39 | snippet, 40 | har.comment ? har.comment : undefined 41 | ) 42 | ); 43 | } 44 | 45 | // use first element since method, url, and description 46 | // are the same for all elements 47 | return { 48 | method: hars[0].method, 49 | url: hars[0].url, 50 | description: hars[0].description, 51 | resource: getResourceName(hars[0].url), 52 | snippets: snippets, 53 | }; 54 | }; 55 | 56 | /** 57 | * Return snippets for all endpoints in the given OpenAPI document. 58 | * 59 | * @param {object} openApi OpenAPI document 60 | * @param {array} targets List of languages to create snippets in, e.g, 61 | * ['cURL', 'Node'] 62 | */ 63 | const getSnippets = function (openApi, targets) { 64 | const endpointHarInfoList = OpenAPIToHar.getAll(openApi); 65 | 66 | const results = []; 67 | for (let i in endpointHarInfoList) { 68 | // create HTTPSnippet object: 69 | const harInfo = endpointHarInfoList[i]; 70 | const snippets = []; 71 | for (const har of harInfo.hars) { 72 | const snippet = new HTTPSnippet(har); 73 | snippets.push(...getSnippetsForTargets(targets, snippet, har.comment)); 74 | } 75 | 76 | results.push({ 77 | method: harInfo.method, 78 | url: harInfo.url, 79 | description: harInfo.description, 80 | resource: getResourceName(harInfo.url), 81 | snippets, 82 | }); 83 | } 84 | 85 | // sort results: 86 | results.sort((a, b) => { 87 | if (a.resource < b.resource) { 88 | return -1; 89 | } else if (a.resource > b.resource) { 90 | return 1; 91 | } else { 92 | return getMethodOrder(a.method.toLowerCase(), b.method.toLowerCase()); 93 | } 94 | }); 95 | 96 | return results; 97 | }; 98 | 99 | /** 100 | * Determine the order of HTTP methods. 101 | * 102 | * @param {string} a One HTTP verb in lower case 103 | * @param {string} b Another HTTP verb in lower case 104 | * @return {number} The order instruction for the given HTTP verbs 105 | */ 106 | const getMethodOrder = function (a, b) { 107 | const order = ['get', 'post', 'put', 'delete', 'patch']; 108 | if (order.indexOf(a) === -1) { 109 | return 1; 110 | } else if (order.indexOf(b) === -1) { 111 | return -1; 112 | } else if (order.indexOf(a) < order.indexOf(b)) { 113 | return -1; 114 | } else if (order.indexOf(a) > order.indexOf(b)) { 115 | return 1; 116 | } else { 117 | return 0; 118 | } 119 | }; 120 | 121 | /** 122 | * Determines the name of the resource exposed by the method. 123 | * E.g., ../users/{userId} --> users 124 | * 125 | * @param {string} urlStr The OpenAPI path definition 126 | * @return {string} The determined resource name 127 | */ 128 | const getResourceName = function (urlStr) { 129 | const pathComponents = urlStr.split('/'); 130 | for (let i = pathComponents.length - 1; i >= 0; i--) { 131 | const cand = pathComponents[i]; 132 | if (cand !== '' && !/^{/.test(cand)) { 133 | return cand; 134 | } 135 | } 136 | }; 137 | 138 | /** 139 | * Format the given target by splitting up language and library and making sure 140 | * that HTTP Snippet supports them. 141 | * 142 | * @param {string} targetStr String defining a target, e.g., node_request 143 | * @return {object} Object with formatted target, or null 144 | */ 145 | const formatTarget = function (targetStr) { 146 | const language = targetStr.split('_')[0]; 147 | const title = capitalizeFirstLetter(language); 148 | let library = targetStr.split('_')[1]; 149 | 150 | const validTargets = HTTPSnippet.availableTargets(); 151 | let validLanguage = false; 152 | let validLibrary = false; 153 | for (let i in validTargets) { 154 | const target = validTargets[i]; 155 | if (language === target.key) { 156 | validLanguage = true; 157 | if (typeof library === 'undefined') { 158 | library = target.default; 159 | validLibrary = true; 160 | } else { 161 | for (let j in target.clients) { 162 | const client = target.clients[j]; 163 | if (library === client.key) { 164 | validLibrary = true; 165 | break; 166 | } 167 | } 168 | } 169 | } 170 | } 171 | 172 | if (!validLanguage || !validLibrary) { 173 | return null; 174 | } 175 | 176 | return { 177 | title: 178 | typeof library !== 'undefined' 179 | ? title + ' + ' + capitalizeFirstLetter(library) 180 | : title, 181 | language, 182 | library, 183 | }; 184 | }; 185 | 186 | /** 187 | * Generate code snippets for each of the supplied targets 188 | * 189 | * @param targets {array} List of language targets to generate code for 190 | * @param snippet {Object} Snippet object from httpsnippet to convert into the target objects 191 | * @param mimeType {string | undefined} Additional information to add uniqueness to the produced snippets 192 | */ 193 | const getSnippetsForTargets = function (targets, snippet, mimeType) { 194 | const snippets = []; 195 | for (let j in targets) { 196 | const target = formatTarget(targets[j]); 197 | if (!target) throw new Error('Invalid target: ' + targets[j]); 198 | snippets.push({ 199 | id: targets[j], 200 | ...(mimeType !== undefined && { mimeType: mimeType }), 201 | title: target.title, 202 | content: snippet.convert( 203 | target.language, 204 | typeof target.library !== 'undefined' ? target.library : null 205 | ), 206 | }); 207 | } 208 | return snippets; 209 | }; 210 | 211 | const capitalizeFirstLetter = function (string) { 212 | return string.charAt(0).toUpperCase() + string.slice(1); 213 | }; 214 | 215 | module.exports = { 216 | getSnippets, 217 | getEndpointSnippets, 218 | }; 219 | 220 | // The if is only for when this is run from the browser 221 | if (typeof window !== 'undefined') { 222 | // grab existing namespace object, or create a blank object 223 | // if it doesn't exist 224 | let OpenAPISnippets = window.OpenAPISnippets || {}; 225 | 226 | // define that object 227 | OpenAPISnippets = { 228 | getSnippets, 229 | getEndpointSnippets, 230 | }; 231 | 232 | // replace/create the global namespace 233 | window.OpenAPISnippets = OpenAPISnippets; 234 | } 235 | -------------------------------------------------------------------------------- /openapi-to-har.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Translates given OpenAPI document to an array of HTTP Archive (HAR) 1.2 Request Object. 3 | * See more: 4 | * - http://swagger.io/specification/ 5 | * - http://www.softwareishard.com/blog/har-12-spec/#request 6 | * 7 | * Example HAR Request Object: 8 | * "request": { 9 | * "method": "GET", 10 | * "url": "http://www.example.com/path/?param=value", 11 | * "httpVersion": "HTTP/1.1", 12 | * "cookies": [], 13 | * "headers": [], 14 | * "queryString" : [], 15 | * "postData" : {}, 16 | * "headersSize" : 150, 17 | * "bodySize" : 0, 18 | * "comment" : "" 19 | * } 20 | */ 21 | const OpenAPISampler = require('openapi-sampler'); 22 | 23 | /** 24 | * Create HAR Request object for path and method pair described in given OpenAPI 25 | * document. 26 | * 27 | * @param {Object} openApi OpenAPI document 28 | * @param {string} path Key of the path 29 | * @param {string} method Key of the method 30 | * @param {Object} queryParamValues Optional: Values for the query parameters if present 31 | * @return {array} List of HAR Request objects for the endpoint 32 | */ 33 | const createHar = function (openApi, path, method, queryParamValues) { 34 | // if the operational parameter is not provided, set it to empty object 35 | if (typeof queryParamValues === 'undefined') { 36 | queryParamValues = {}; 37 | } 38 | 39 | const baseUrl = getBaseUrl(openApi, path, method); 40 | 41 | const baseHar = { 42 | method: method.toUpperCase(), 43 | url: baseUrl + getFullPath(openApi, path, method), 44 | headers: getHeadersArray(openApi, path, method), 45 | queryString: getQueryStrings(openApi, path, method, queryParamValues), 46 | httpVersion: 'HTTP/1.1', 47 | cookies: getCookies(openApi, path, method), 48 | headersSize: 0, 49 | bodySize: 0, 50 | }; 51 | 52 | let hars = []; 53 | 54 | // get payload data, if available: 55 | const postDatas = getPayloads(openApi, path, method); 56 | 57 | // For each postData create a snippet 58 | if (postDatas.length > 0) { 59 | for (let i in postDatas) { 60 | const postData = postDatas[i]; 61 | const copiedHar = JSON.parse(JSON.stringify(baseHar)); 62 | copiedHar.postData = postData; 63 | copiedHar.comment = postData.mimeType; 64 | copiedHar.headers.push({ 65 | name: 'content-type', 66 | value: postData.mimeType, 67 | }); 68 | hars.push(copiedHar); 69 | } 70 | } else { 71 | hars = [baseHar]; 72 | } 73 | 74 | return hars; 75 | }; 76 | 77 | /** 78 | * Tests `value` to see if it is a primitive. 79 | * @param {*} value - The value to test 80 | * @returns {boolean} - `true` if `value` is a primitive, `false` otherwise 81 | */ 82 | const isPrimitive = function (value) { 83 | if (value === null) return true; 84 | const valueType = typeof value; 85 | if (valueType === 'function' || valueType === 'object') return false; 86 | return true; 87 | }; 88 | 89 | /** 90 | * Returns a string that is used as a prefix before a value in a path parameter 91 | * @param {string} style 92 | * @returns {string} - Returns `.` for label style and `;` for matrix style. Returns '' for any other input. 93 | */ 94 | const getPrefix = function (style) { 95 | if (style === 'label') { 96 | return '.'; 97 | } 98 | if (style === 'matrix') { 99 | return `;`; 100 | } 101 | return ''; 102 | }; 103 | 104 | /** 105 | * Returns the separator character used between elements of a path parameter 106 | * Returns '.' for label style, ';' for matrix style and ',' for all others 107 | * @param {string} style 108 | * @returns 109 | */ 110 | const getSeparator = function (style) { 111 | if (style === 'label') return '.'; 112 | if (style === 'matrix') return ';'; 113 | return ','; 114 | }; 115 | 116 | /** 117 | * Returns a "parameter identifier" used in matrix style path parameters. For all other styles 118 | * it returns '' 119 | * @param {string} style 120 | * @param {string} name - The parameter name 121 | * @returns {string} - The empty string if `style` is not `matrix`, else a string in the format `;{name}=` 122 | */ 123 | const getParamId = function (style, name) { 124 | if (style === 'matrix') return `${name}=`; 125 | return ''; 126 | }; 127 | 128 | /** 129 | * Returns the default style for the location per OpenAPI 3.0.3 spec 130 | * @param {*} location 131 | * @returns 132 | */ 133 | const getDefaultStyleForLocation = function (location) { 134 | if (location === 'path' || location === 'header') { 135 | return 'simple'; 136 | } else if (location === 'query' || location === 'cookie') { 137 | return 'form'; 138 | } 139 | }; 140 | 141 | /** 142 | * Returns the default value of explode for the given style per OpenAPI 3.0.3 spec 143 | * @param {*} style 144 | * @returns 145 | */ 146 | const getDefaultExplodeForStyle = function (style) { 147 | return style === 'form'; 148 | }; 149 | 150 | /** 151 | * Returns the correct array element separator for unexploded query parameters 152 | * based on style. If style is spaceDelimited this returns `%20` (the encoded string for 153 | * space character). If style is pipeDelimited this returns '|'; else it returns ',' 154 | * @param {*} style 155 | * @returns 156 | */ 157 | const getArrayElementSeparator = function (style) { 158 | let separator = ','; 159 | if (style === 'spaceDelimited') { 160 | separator = ' '; 161 | } else if (style === 'pipeDelimited') { 162 | separator = '|'; 163 | } 164 | return separator; 165 | }; 166 | 167 | /** 168 | * Returns a string representation of `obj`. Each key value pair is separated by 169 | * a `keyValueSeparator` and each pair is separated by a `pairSeparator`. 170 | * 171 | * @param {*} obj 172 | * @param {*} keyValueSeparator 173 | * @param {*} pairSeparator 174 | * @example 175 | * // returns "firstName=Alex,age=34" 176 | * objectJoin({ firstName: 'Alex', age: 34 }, '=', ',') 177 | * @returns 178 | */ 179 | const objectJoin = function ( 180 | obj, 181 | keyValueSeparator = ',', 182 | pairSeparator = ',' 183 | ) { 184 | return Object.entries(obj) 185 | .map(([k, v]) => `${k}${keyValueSeparator}${v}`) 186 | .join(pairSeparator); 187 | }; 188 | 189 | /** 190 | * @typedef {object} HarParameterObject - An object that describes a parameter in a HAR 191 | * @property {string} name - The name of the parameter 192 | * @property {string} value - The value of the parameter 193 | */ 194 | 195 | /** 196 | * Returns an array of HAR parameter objects for the specified parameter and value. 197 | * 198 | * While it is quite often that a singleton array is returned, when `explode` is 199 | * true multiple objects may be returned. 200 | * 201 | * See https://swagger.io/docs/specification/serialization for the logic of how value of 202 | * the return objects are calculated 203 | * 204 | * @param {Object} parameter - An OpenAPI Parameter object 205 | * @param {string} name - The name of the parameter 206 | * @param {string} in - One of the values: `path`, `query`, `header`, `cookie` 207 | * @param {string} [style] - Optional: One of the OpenAPI styles {e.g. form, simple, label, matrix, ...} 208 | * @param {boolean} [explode] - Optional: Whether or not arrays and objects should be exploded 209 | * @param {*} value - The value to use in the query string object. Since `parameter` 210 | * has many properties that could be a candidate for the value this 211 | * parameter is used to explicitly state which value should be used. 212 | * @return {HarParameterObject[]} - An array of query string objects 213 | */ 214 | const createHarParameterObjects = function ( 215 | { name, in: location, style, explode }, 216 | value 217 | ) { 218 | if (!name || !location || typeof value === 'undefined') { 219 | throw 'Required parameters missing'; 220 | } 221 | 222 | const prefix = getPrefix(style); 223 | const paramId = getParamId(style, name); 224 | 225 | if (isPrimitive(value)) { 226 | return [{ name, value: prefix + paramId + value }]; 227 | } 228 | 229 | const objects = []; 230 | style = style ?? getDefaultStyleForLocation(location); 231 | explode = explode ?? getDefaultExplodeForStyle(style); 232 | 233 | if (location === 'query' || location === 'cookie') { 234 | const separator = getArrayElementSeparator(style); 235 | if (Array.isArray(value)) { 236 | if (explode) { 237 | objects.push( 238 | ...value.map((entry) => { 239 | return { name, value: entry + '' }; 240 | }) 241 | ); 242 | } else { 243 | objects.push({ name, value: value.join(separator) }); 244 | } 245 | } else if (value && typeof value === 'object') { 246 | if (style === 'deepObject') { 247 | objects.push( 248 | ...Object.entries(value).map(([k, v]) => { 249 | return { name: `${name}[${k}]`, value: v + '' }; 250 | }) 251 | ); 252 | } else if (explode) { 253 | objects.push( 254 | ...Object.entries(value).map(([k, v]) => { 255 | return { name: k, value: v + '' }; 256 | }) 257 | ); 258 | } else { 259 | objects.push({ 260 | name, 261 | value: objectJoin(value), 262 | }); 263 | } 264 | } 265 | } else if (location === 'path' || location === 'header') { 266 | const separator = getSeparator(style); 267 | 268 | if (Array.isArray(value)) { 269 | objects.push({ 270 | name, 271 | value: 272 | prefix + paramId + value.join(explode ? separator + paramId : ','), 273 | }); 274 | } else if (value && typeof value === 'object') { 275 | if (explode) { 276 | objects.push({ 277 | name, 278 | value: prefix + objectJoin(value, '=', separator), 279 | }); 280 | } else { 281 | objects.push({ 282 | name, 283 | value: prefix + paramId + objectJoin(value), 284 | }); 285 | } 286 | } 287 | } 288 | 289 | return objects; 290 | }; 291 | 292 | /** 293 | * Get the payload definition for the given endpoint (path + method) from the 294 | * given OAI specification. References within the payload definition are 295 | * resolved. 296 | * 297 | * @param {object} openApi 298 | * @param {string} path 299 | * @param {string} method 300 | * @return {array} A list of payload objects 301 | */ 302 | const getPayloads = function (openApi, path, method) { 303 | if (typeof openApi.paths[path][method].parameters !== 'undefined') { 304 | for (let i in openApi.paths[path][method].parameters) { 305 | const param = openApi.paths[path][method].parameters[i]; 306 | if ( 307 | typeof param.in !== 'undefined' && 308 | param.in.toLowerCase() === 'body' && 309 | typeof param.schema !== 'undefined' 310 | ) { 311 | try { 312 | const sample = OpenAPISampler.sample( 313 | param.schema, 314 | { skipReadOnly: true }, 315 | openApi 316 | ); 317 | return [ 318 | { 319 | mimeType: 'application/json', 320 | text: JSON.stringify(sample), 321 | }, 322 | ]; 323 | } catch (err) { 324 | console.log(err); 325 | return null; 326 | } 327 | } 328 | } 329 | } 330 | 331 | if ( 332 | openApi.paths[path][method].requestBody && 333 | openApi.paths[path][method].requestBody['$ref'] 334 | ) { 335 | openApi.paths[path][method].requestBody = resolveRef( 336 | openApi, 337 | openApi.paths[path][method].requestBody['$ref'] 338 | ); 339 | } 340 | 341 | const payloads = []; 342 | if ( 343 | openApi.paths[path][method].requestBody && 344 | openApi.paths[path][method].requestBody.content 345 | ) { 346 | [ 347 | 'application/json', 348 | 'application/x-www-form-urlencoded', 349 | 'multipart/form-data', 350 | ].forEach((type) => { 351 | const content = openApi.paths[path][method].requestBody.content[type]; 352 | if (content && content.schema) { 353 | const sample = OpenAPISampler.sample( 354 | content.schema, 355 | { skipReadOnly: true }, 356 | openApi 357 | ); 358 | if (type === 'application/json') { 359 | payloads.push({ 360 | mimeType: type, 361 | text: JSON.stringify(sample), 362 | }); 363 | } else if (type === 'multipart/form-data') { 364 | if (sample !== undefined) { 365 | const params = []; 366 | Object.keys(sample).forEach((key) => { 367 | let value = sample[key]; 368 | if (typeof sample[key] !== 'string') { 369 | value = JSON.stringify(sample[key]); 370 | } 371 | params.push({ name: key, value: value }); 372 | }); 373 | payloads.push({ 374 | mimeType: type, 375 | params: params, 376 | }); 377 | } 378 | } else if (type == 'application/x-www-form-urlencoded') { 379 | if (sample === undefined) return null; 380 | 381 | const params = []; 382 | Object.keys(sample).map((key) => 383 | params.push({ 384 | name: encodeURIComponent(key).replace(/\%20/g, '+'), 385 | value: encodeURIComponent(sample[key]).replace(/\%20/g, '+'), 386 | }) 387 | ); 388 | 389 | payloads.push({ 390 | mimeType: 'application/x-www-form-urlencoded', 391 | params: params, 392 | text: Object.keys(params) 393 | .map((key) => key + '=' + sample[key]) 394 | .join('&'), 395 | }); 396 | } 397 | } 398 | }); 399 | } 400 | return payloads; 401 | }; 402 | 403 | /** 404 | * Gets the base URL constructed from the given openApi. 405 | * 406 | * @param {Object} openApi OpenAPI document 407 | * @return {string} Base URL 408 | */ 409 | const getBaseUrl = function (openApi, path, method) { 410 | if (openApi.paths[path][method].servers) 411 | return openApi.paths[path][method].servers[0].url; 412 | if (openApi.paths[path].servers) return openApi.paths[path].servers[0].url; 413 | if (openApi.servers) return openApi.servers[0].url; 414 | 415 | let baseUrl = ''; 416 | if (typeof openApi.schemes !== 'undefined') { 417 | baseUrl += openApi.schemes[0]; 418 | } else { 419 | baseUrl += 'http'; 420 | } 421 | 422 | if (openApi.basePath === '/') { 423 | baseUrl += '://' + openApi.host; 424 | } else { 425 | baseUrl += '://' + openApi.host + openApi.basePath; 426 | } 427 | 428 | return baseUrl; 429 | }; 430 | 431 | /** 432 | * Gets an object describing the parameters (header or query) in a given OpenAPI method 433 | * @param {Object} openApi OpenApi document 434 | * @param {Object} param parameter values to use in snippet 435 | * @param {string} location One of `path`, `header`, `query`, `cookie` 436 | * @param {Object} values Optional: query parameter values to use in the snippet if present 437 | * @return {HarParameterObject[]} Array of objects describing the parameters in a given OpenAPI method or path 438 | */ 439 | const getParameterValues = function (openApi, param, location, values) { 440 | let value = 441 | 'SOME_' + (param.type || param.schema.type).toUpperCase() + '_VALUE'; 442 | if (location === 'path') { 443 | // then default to the original place holder value (e.b. '{id}') 444 | value = `{${param.name}}`; 445 | } 446 | 447 | if (values && typeof values[param.name] !== 'undefined') { 448 | value = values[param.name]; 449 | } else if (typeof param.example !== 'undefined') { 450 | value = param.example; 451 | } else if (typeof param.examples !== 'undefined') { 452 | let firstExample = Object.values(param.examples)[0]; 453 | if ( 454 | typeof firstExample['$ref'] === 'string' && 455 | /^#/.test(firstExample['$ref']) 456 | ) { 457 | firstExample = resolveRef(openApi, firstExample['$ref']); 458 | } 459 | value = firstExample.value; 460 | } else if ( 461 | typeof param.schema !== 'undefined' && 462 | typeof param.schema.example !== 'undefined' 463 | ) { 464 | value = param.schema.example; 465 | } else if (typeof param.default !== 'undefined') { 466 | value = param.default; 467 | } 468 | 469 | return createHarParameterObjects(param, value); 470 | }; 471 | 472 | /** 473 | * Parse parameter object into query string objects 474 | * 475 | * @param {Object} openApi OpenApi document 476 | * @param {Object} parameters Objects described in the document to parse into the query string 477 | * @param {string} location One of `path`, `query`, `header` or `cookie` 478 | * @param {Object} values Optional: query parameter values to use in the snippet if present 479 | * @return {Object.} Object describing the parameters for a method or path. 480 | * Each key in the return object will have at least one entry it's is value array. But exploded values 481 | * in query parameters may have more than one. 482 | */ 483 | const parseParametersToQuery = function ( 484 | openApi, 485 | parameters, 486 | location, 487 | values 488 | ) { 489 | /** @type {Object.} */ 490 | const queryStrings = {}; 491 | 492 | for (let i in parameters) { 493 | let param = parameters[i]; 494 | if (typeof param['$ref'] === 'string' && /^#/.test(param['$ref'])) { 495 | param = resolveRef(openApi, param['$ref']); 496 | } 497 | if (typeof param.schema !== 'undefined') { 498 | if ( 499 | typeof param.schema['$ref'] === 'string' && 500 | /^#/.test(param.schema['$ref']) 501 | ) { 502 | param.schema = resolveRef(openApi, param.schema['$ref']); 503 | if (typeof param.schema.type === 'undefined') { 504 | // many schemas don't have an explicit type 505 | param.schema.type = 'object'; 506 | } 507 | } 508 | } 509 | if ( 510 | typeof param.in !== 'undefined' && 511 | param.in.toLowerCase() === location 512 | ) { 513 | // param.name is a safe key, because the spec defines 514 | // that name MUST be unique 515 | queryStrings[param.name] = getParameterValues( 516 | openApi, 517 | param, 518 | location, 519 | values 520 | ); 521 | } 522 | } 523 | 524 | return queryStrings; 525 | }; 526 | 527 | /** 528 | * Examines all of the parameters in the specified path and operation looking 529 | * for those of the specific `location` specified 530 | * It resolves any references to schemas or parameters as it does so. 531 | * It examines the `example`, `examples`, `schema.example` and `default` 532 | * keys looking for one sample value. It then returns an array of HAR 533 | * parameter objects 534 | * @param {Object} openApi OpenAPI document 535 | * @param {string} path Key of the path 536 | * @param {string} method Key of the method 537 | * @param {string} location One of `path`, `query`, `header`, `cookie` 538 | * @param {HarParameterObject[]} - A list of parameter objects for the specified location 539 | * @returns 540 | */ 541 | const getParameterCollectionIn = function ( 542 | openApi, 543 | path, 544 | method, 545 | location, 546 | values 547 | ) { 548 | // Set the optional parameter if it's not provided 549 | if (typeof values === 'undefined') { 550 | values = {}; 551 | } 552 | 553 | /** @type {Object.} */ 554 | let pathParameters = {}; 555 | 556 | /** @type {Object.} */ 557 | let operationParameters = {}; 558 | 559 | // First get any parameters from the path 560 | if (typeof openApi.paths[path].parameters !== 'undefined') { 561 | pathParameters = parseParametersToQuery( 562 | openApi, 563 | openApi.paths[path].parameters, 564 | location, 565 | values 566 | ); 567 | } 568 | 569 | if (typeof openApi.paths[path][method].parameters !== 'undefined') { 570 | operationParameters = parseParametersToQuery( 571 | openApi, 572 | openApi.paths[path][method].parameters, 573 | location, 574 | values 575 | ); 576 | } 577 | 578 | // Merge parameters, with method overriding path 579 | // from the spec: 580 | // If a parameter is already defined at the Path Item, the new definition will override 581 | // it but can never remove it. 582 | // https://swagger.io/specification/ 583 | 584 | /** @type {Object. entry); 590 | }; 591 | 592 | /** 593 | * Get array of objects describing the query parameters for a path and method 594 | * pair described in the given OpenAPI document. 595 | * 596 | * @param {Object} openApi OpenApi document 597 | * @param {string} path Key of the path 598 | * @param {string} method Key of the method 599 | * @param {Object} values Optional: query parameter values to use in the snippet if present 600 | * @return {HarParameterObject[]} List of objects describing the query strings 601 | */ 602 | const getQueryStrings = function (openApi, path, method, values) { 603 | return getParameterCollectionIn(openApi, path, method, 'query', values); 604 | }; 605 | 606 | /** 607 | * Return the path with the parameters example values used if specified. 608 | * 609 | * @param {Object} openApi OpenApi document 610 | * @param {string} path Key of the path 611 | * @param {string} method Key of the method 612 | * @return {string} Full path including example values 613 | */ 614 | const getFullPath = function (openApi, path, method) { 615 | let fullPath = path; 616 | 617 | const pathParameters = getParameterCollectionIn( 618 | openApi, 619 | path, 620 | method, 621 | 'path' 622 | ); 623 | pathParameters.forEach(({ name, value }) => { 624 | fullPath = fullPath.replace('{' + name + '}', value); 625 | }); 626 | 627 | return fullPath; 628 | }; 629 | 630 | /** 631 | * Get an array of objects providing sample values for cookies 632 | * 633 | * @param {Object} openApi OpenAPI document 634 | * @param {string} path Key of the path 635 | * @param {string} method Key of the method 636 | */ 637 | const getCookies = function (openApi, path, method) { 638 | return getParameterCollectionIn(openApi, path, method, 'cookie'); 639 | }; 640 | 641 | /** 642 | * Get an array of objects describing the header for a path and method pair 643 | * described in the given OpenAPI document. 644 | * 645 | * @param {Object} openApi OpenAPI document 646 | * @param {string} path Key of the path 647 | * @param {string} method Key of the method 648 | * @return {HarParameterObject[]} List of objects describing the header 649 | */ 650 | const getHeadersArray = function (openApi, path, method) { 651 | const headers = []; 652 | const pathObj = openApi.paths[path][method]; 653 | 654 | // 'accept' header: 655 | if (typeof pathObj.consumes !== 'undefined') { 656 | for (let i in pathObj.consumes) { 657 | const type = pathObj.consumes[i]; 658 | headers.push({ 659 | name: 'accept', 660 | value: type, 661 | }); 662 | } 663 | } 664 | 665 | // headers defined in path object: 666 | headers.push(...getParameterCollectionIn(openApi, path, method, 'header')); 667 | 668 | // security: 669 | let basicAuthDef; 670 | let apiKeyAuthDef; 671 | let oauthDef; 672 | if (typeof pathObj.security !== 'undefined') { 673 | for (var l in pathObj.security) { 674 | const secScheme = Object.keys(pathObj.security[l])[0]; 675 | const secDefinition = openApi.securityDefinitions 676 | ? openApi.securityDefinitions[secScheme] 677 | : openApi.components.securitySchemes[secScheme]; 678 | const authType = secDefinition.type.toLowerCase(); 679 | let authScheme = null; 680 | 681 | if (authType !== 'apikey' && secDefinition.scheme != null) { 682 | authScheme = secDefinition.scheme.toLowerCase(); 683 | } 684 | 685 | switch (authType) { 686 | case 'basic': 687 | basicAuthDef = secScheme; 688 | break; 689 | case 'apikey': 690 | if (secDefinition.in === 'header') { 691 | apiKeyAuthDef = secDefinition; 692 | } 693 | break; 694 | case 'oauth2': 695 | oauthDef = secScheme; 696 | break; 697 | case 'http': 698 | switch (authScheme) { 699 | case 'bearer': 700 | oauthDef = secScheme; 701 | break; 702 | case 'basic': 703 | basicAuthDef = secScheme; 704 | break; 705 | } 706 | break; 707 | } 708 | } 709 | } else if (typeof openApi.security !== 'undefined') { 710 | // Need to check OAS 3.0 spec about type http and scheme 711 | for (let m in openApi.security) { 712 | const secScheme = Object.keys(openApi.security[m])[0]; 713 | const secDefinition = openApi.components.securitySchemes[secScheme]; 714 | const authType = secDefinition.type.toLowerCase(); 715 | let authScheme = null; 716 | 717 | if (authType !== 'apikey' && authType !== 'oauth2') { 718 | authScheme = secDefinition.scheme.toLowerCase(); 719 | } 720 | 721 | switch (authType) { 722 | case 'http': 723 | switch (authScheme) { 724 | case 'bearer': 725 | oauthDef = secScheme; 726 | break; 727 | case 'basic': 728 | basicAuthDef = secScheme; 729 | break; 730 | } 731 | break; 732 | case 'basic': 733 | basicAuthDef = secScheme; 734 | break; 735 | case 'apikey': 736 | if (secDefinition.in === 'header') { 737 | apiKeyAuthDef = secDefinition; 738 | } 739 | break; 740 | case 'oauth2': 741 | oauthDef = secScheme; 742 | break; 743 | } 744 | } 745 | } 746 | 747 | if (basicAuthDef) { 748 | headers.push({ 749 | name: 'Authorization', 750 | value: 'Basic ' + 'REPLACE_BASIC_AUTH', 751 | }); 752 | } else if (apiKeyAuthDef) { 753 | headers.push({ 754 | name: apiKeyAuthDef.name, 755 | value: 'REPLACE_KEY_VALUE', 756 | }); 757 | } else if (oauthDef) { 758 | headers.push({ 759 | name: 'Authorization', 760 | value: 'Bearer ' + 'REPLACE_BEARER_TOKEN', 761 | }); 762 | } 763 | 764 | return headers; 765 | }; 766 | 767 | /** 768 | * Produces array of HAR files for given OpenAPI document 769 | * 770 | * @param {object} openApi OpenAPI document 771 | * @param {Function} callback 772 | */ 773 | const openApiToHarList = function (openApi) { 774 | try { 775 | // iterate openApi and create har objects: 776 | const harList = []; 777 | for (let path in openApi.paths) { 778 | for (let method in openApi.paths[path]) { 779 | const url = getBaseUrl(openApi, path, method) + path; 780 | const hars = createHar(openApi, path, method); 781 | // need to push multiple here 782 | harList.push({ 783 | method: method.toUpperCase(), 784 | url: url, 785 | description: 786 | openApi.paths[path][method].description || 787 | 'No description available', 788 | hars: hars, 789 | }); 790 | } 791 | } 792 | 793 | return harList; 794 | } catch (e) { 795 | console.log(e); 796 | } 797 | }; 798 | 799 | /** 800 | * Returns the value referenced in the given reference string 801 | * 802 | * @param {object} openApi OpenAPI document 803 | * @param {string} ref A reference string 804 | * @return {any} 805 | */ 806 | const resolveRef = function (openApi, ref) { 807 | const parts = ref.split('/'); 808 | 809 | if (parts.length <= 1) return {}; // = 3 810 | 811 | const recursive = function (obj, index) { 812 | if (index + 1 < parts.length) { 813 | // index = 1 814 | let newCount = index + 1; 815 | return recursive(obj[parts[index]], newCount); 816 | } else { 817 | return obj[parts[index]]; 818 | } 819 | }; 820 | return recursive(openApi, 1); 821 | }; 822 | 823 | module.exports = { 824 | getAll: openApiToHarList, 825 | getEndpoint: createHar, 826 | createHarParameterObjects, 827 | }; 828 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openapi-snippet", 3 | "version": "0.14.0", 4 | "description": "Generates code snippets from Open API (previously Swagger) documents.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ErikWittern/openapi-snippet" 8 | }, 9 | "keywords": [ 10 | "HTTP", 11 | "code snippets", 12 | "OpenAPI Specification", 13 | "Swagger" 14 | ], 15 | "author": "Erik Wittern", 16 | "license": "MIT", 17 | "main": "index.js", 18 | "scripts": { 19 | "test": "node test/test.js | tap-spec", 20 | "build": "mkdir -p dist && browserify -g uglifyify ./index.js > ./dist/openapisnippet.min.js" 21 | }, 22 | "dependencies": { 23 | "httpsnippet": "^2.0.0", 24 | "openapi-sampler": "^1.0.0-beta.14" 25 | }, 26 | "devDependencies": { 27 | "browserify": "^16.2.3", 28 | "prettier": "2.3.0", 29 | "tap-spec": "^5.0.0", 30 | "tape": "^4.10.1", 31 | "uglifyify": "^5.0.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/form_data_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "patch": { 26 | "description": "Creates a new pet in the store. Duplicates are allowed", 27 | "operationId": "addPet", 28 | "requestBody": { 29 | "content": { 30 | "multipart/form-data": { 31 | "schema": { 32 | "$ref": "#/components/schemas/ModifyPet" 33 | } 34 | } 35 | } 36 | }, 37 | "responses": { 38 | "200": { 39 | "description": "pet response", 40 | "content": { 41 | "application/json": { 42 | "schema": { 43 | "$ref": "#/components/schemas/Pet" 44 | } 45 | } 46 | } 47 | }, 48 | "default": { 49 | "description": "unexpected error", 50 | "content": { 51 | "application/json": { 52 | "schema": { 53 | "$ref": "#/components/schemas/Error" 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | "/pets/{id}/updatetags": { 62 | "patch": { 63 | "description": "Updates tags on a specific pet", 64 | "operationId": "updatePetTags", 65 | "requestBody": { 66 | "content": { 67 | "multipart/form-data": { 68 | "schema": { 69 | "$ref": "#/components/schemas/UpdateTags" 70 | } 71 | } 72 | } 73 | }, 74 | "responses": { 75 | "200": { 76 | "description": "pet response", 77 | "content": { 78 | "application/json": { 79 | "schema": { 80 | "$ref": "#/components/schemas/Pet" 81 | } 82 | } 83 | } 84 | }, 85 | "default": { 86 | "description": "unexpected error", 87 | "content": { 88 | "application/json": { 89 | "schema": { 90 | "$ref": "#/components/schemas/Error" 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | }, 98 | "/pets/{id}/feedingschedule": { 99 | "patch": { 100 | "description": "Updates feeding schedule for specific pet", 101 | "operationId": "updatePetFeedingSchedule", 102 | "requestBody": { 103 | "content": { 104 | "multipart/form-data": { 105 | "schema": { 106 | "$ref": "#/components/schemas/UpdateFeedingSchedule" 107 | } 108 | } 109 | } 110 | }, 111 | "responses": { 112 | "200": { 113 | "description": "pet response", 114 | "content": { 115 | "application/json": { 116 | "schema": { 117 | "$ref": "#/components/schemas/Pet" 118 | } 119 | } 120 | } 121 | }, 122 | "default": { 123 | "description": "unexpected error", 124 | "content": { 125 | "application/json": { 126 | "schema": { 127 | "$ref": "#/components/schemas/Error" 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | }, 136 | "components": { 137 | "schemas": { 138 | "ModifyPet": { 139 | "properties": { 140 | "pet[name]": { 141 | "type": "string" 142 | }, 143 | "pet[tag]": { 144 | "type": "string" 145 | } 146 | } 147 | }, 148 | "UpdateTags": { 149 | "properties": { 150 | "pet[tags]": { 151 | "type": "array", 152 | "items": { 153 | "type": "string" 154 | } 155 | } 156 | } 157 | }, 158 | "UpdateFeedingSchedule": { 159 | "properties": { 160 | "pet[feedingSchedule]": { 161 | "type": "object", 162 | "properties": { 163 | "time": { 164 | "type": "string" 165 | }, 166 | "food": { 167 | "type": "string" 168 | } 169 | } 170 | } 171 | } 172 | } 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /test/form_urlencoded_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Sample API", 6 | "description": "A sample API to demonstrate x-www-form-encoded request body example" 7 | }, 8 | "servers": [ 9 | { 10 | "url": "http://auth.io/api" 11 | } 12 | ], 13 | "paths": { 14 | "/auth/token": { 15 | "post": { 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/x-www-form-urlencoded": { 20 | "schema": { 21 | "type": "object", 22 | "required": ["id", "secret"], 23 | "properties": { 24 | "id": { 25 | "type": "string", 26 | "example": "id example value" 27 | }, 28 | "secret": { 29 | "type": "string", 30 | "example": "secret example value" 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/ibm_watson_alchemy_data_news_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "title": "IBM Alchemy Data News", 5 | "version": "1.0", 6 | "description": "Alchemy Data News provides news and blog content enriched with natural language processing to allow for highly targeted search and trend analysis. Now you can query the world's news sources and blogs like a database.", 7 | "x-tags": ["News", "Natural Language Processing", "Blogs"], 8 | "contact": { "url": "https://support.ng.bluemix.net/supportticket/" } 9 | }, 10 | "externalDocs": { 11 | "url": "https://www.ibm.com/watson/developercloud/alchemydata-news/api/v1/" 12 | }, 13 | "host": "gateway-a.watsonplatform.net", 14 | "schemes": ["https"], 15 | "basePath": "/calls", 16 | "paths": { 17 | "/data/GetNews": { 18 | "get": { 19 | "tags": ["News"], 20 | "summary": "Analyze news", 21 | "description": "Analyze news using Natural Language Processing (NLP) queries and sophisticated filters.", 22 | "operationId": "GetNews", 23 | "produces": ["application/json", "application/xml"], 24 | "parameters": [ 25 | { 26 | "in": "query", 27 | "description": "API key (optional in the API explorer)", 28 | "name": "apikey", 29 | "required": true, 30 | "type": "string" 31 | }, 32 | { 33 | "in": "query", 34 | "description": "Output mode", 35 | "name": "outputMode", 36 | "type": "string", 37 | "enum": ["xml", "json"], 38 | "default": "json" 39 | }, 40 | { 41 | "in": "query", 42 | "description": "Start date", 43 | "name": "start", 44 | "required": true, 45 | "type": "string", 46 | "default": "now-1d" 47 | }, 48 | { 49 | "in": "query", 50 | "description": "End date", 51 | "name": "end", 52 | "required": true, 53 | "type": "string", 54 | "default": "now" 55 | }, 56 | { 57 | "in": "query", 58 | "description": "Maximum results", 59 | "name": "maxResults", 60 | "default": 10, 61 | "type": "integer" 62 | }, 63 | { 64 | "in": "query", 65 | "description": "Time slice", 66 | "name": "timeSlice", 67 | "type": "string" 68 | }, 69 | { 70 | "in": "query", 71 | "description": "Fields to return for each document (comma separated). e.g. enriched.url.title,enriched.url.author,enriched.url.keywords", 72 | "name": "return", 73 | "type": "string", 74 | "collectionFormat": "csv" 75 | }, 76 | { 77 | "in": "query", 78 | "description": "Example filter query parameter (title relations)", 79 | "name": "q.enriched.url.enrichedTitle.relations.relation", 80 | "type": "string" 81 | }, 82 | { 83 | "in": "query", 84 | "description": "Example filter query parameter (title entity)", 85 | "name": "q.enriched.url.enrichedTitle.entities.entity", 86 | "type": "string" 87 | }, 88 | { 89 | "in": "query", 90 | "description": "Example filter query parameter (title taxonomy)", 91 | "name": "q.enriched.url.enrichedTitle.taxonomy.taxonomy_", 92 | "type": "string" 93 | }, 94 | { 95 | "in": "query", 96 | "description": "Example filter query parameter (sentiment)", 97 | "name": "q.enriched.url.enrichedTitle.docSentiment.type", 98 | "type": "string" 99 | } 100 | ], 101 | "responses": { 102 | "200": { 103 | "description": "OK", 104 | "schema": { "$ref": "#/definitions/NewsResponse" } 105 | } 106 | }, 107 | "x-apih-advice": { 108 | "totalUsageCount": 26, 109 | "topQueryParams": [ 110 | { 111 | "paramName": "apikey", 112 | "paramValues": [ 113 | { 114 | "value": "", 115 | "count": 3, 116 | "source": [ 117 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 118 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 119 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221" 120 | ] 121 | }, 122 | { 123 | "value": "", 124 | "count": 2, 125 | "source": [ 126 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 127 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64" 128 | ] 129 | }, 130 | { 131 | "value": "", 132 | "count": 2, 133 | "source": [ 134 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 135 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 136 | ] 137 | }, 138 | { 139 | "value": "", 140 | "count": 2, 141 | "source": [ 142 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 143 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56" 144 | ] 145 | } 146 | ], 147 | "bestSources": null, 148 | "count": 10 149 | }, 150 | { 151 | "paramName": "end", 152 | "paramValues": [ 153 | { 154 | "value": "now", 155 | "count": 10, 156 | "source": [ 157 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 158 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 159 | "https://github.com/alexbtk/amos-ss16-proj9/blob/d667a46692f0ea440696a60d6212582f1352006d/src/main/webapp/js/AMOSAlchemy.js#L26", 160 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 161 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64", 162 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56", 163 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 164 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221", 165 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 166 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 167 | ] 168 | } 169 | ], 170 | "bestSources": [ 171 | { 172 | "url": "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 173 | "sourceId": 2 174 | }, 175 | { 176 | "url": "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414", 177 | "sourceId": 3 178 | } 179 | ], 180 | "count": 10 181 | }, 182 | { 183 | "paramName": "outputMode", 184 | "paramValues": [ 185 | { 186 | "value": "json", 187 | "count": 10, 188 | "source": [ 189 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 190 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 191 | "https://github.com/alexbtk/amos-ss16-proj9/blob/d667a46692f0ea440696a60d6212582f1352006d/src/main/webapp/js/AMOSAlchemy.js#L26", 192 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 193 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64", 194 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56", 195 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 196 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221", 197 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 198 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 199 | ] 200 | } 201 | ], 202 | "bestSources": [ 203 | { 204 | "url": "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 205 | "sourceId": 2 206 | }, 207 | { 208 | "url": "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414", 209 | "sourceId": 3 210 | } 211 | ], 212 | "count": 10 213 | }, 214 | { 215 | "paramName": "return", 216 | "paramValues": [ 217 | { 218 | "value": "enriched.url.url,enriched.url.title", 219 | "count": 7, 220 | "source": [ 221 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 222 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 223 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56", 224 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 225 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221", 226 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 227 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 228 | ] 229 | }, 230 | { 231 | "value": "enriched.url.url,enriched.url.title,enriched.url.text", 232 | "count": 2, 233 | "source": [ 234 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 235 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64" 236 | ] 237 | }, 238 | { 239 | "value": "q.enriched.url.title,q.enriched.url.entities", 240 | "count": 1, 241 | "source": [ 242 | "https://github.com/alexbtk/amos-ss16-proj9/blob/d667a46692f0ea440696a60d6212582f1352006d/src/main/webapp/js/AMOSAlchemy.js#L26" 243 | ] 244 | } 245 | ], 246 | "bestSources": null, 247 | "count": 10 248 | }, 249 | { 250 | "paramName": "start", 251 | "paramValues": [ 252 | { 253 | "value": "now-1d", 254 | "count": 5, 255 | "source": [ 256 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 257 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 258 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56", 259 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 260 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221" 261 | ] 262 | }, 263 | { 264 | "value": "now-3.0d", 265 | "count": 2, 266 | "source": [ 267 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 268 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 269 | ] 270 | }, 271 | { 272 | "value": "now-7d", 273 | "count": 2, 274 | "source": [ 275 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 276 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64" 277 | ] 278 | }, 279 | { 280 | "value": "now-3d", 281 | "count": 1, 282 | "source": [ 283 | "https://github.com/alexbtk/amos-ss16-proj9/blob/d667a46692f0ea440696a60d6212582f1352006d/src/main/webapp/js/AMOSAlchemy.js#L26" 284 | ] 285 | } 286 | ], 287 | "bestSources": null, 288 | "count": 10 289 | }, 290 | { 291 | "paramName": "count", 292 | "paramValues": [ 293 | { 294 | "value": "5", 295 | "count": 9, 296 | "source": [ 297 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 298 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 299 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 300 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64", 301 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56", 302 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 303 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221", 304 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 305 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 306 | ] 307 | } 308 | ], 309 | "bestSources": [ 310 | { 311 | "url": "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 312 | "sourceId": 2 313 | }, 314 | { 315 | "url": "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414", 316 | "sourceId": 3 317 | } 318 | ], 319 | "count": 9 320 | }, 321 | { 322 | "paramName": "q.enriched.url.enrichedTitle.keywords.keyword.text", 323 | "paramValues": [ 324 | { 325 | "value": "{candidateNameArray.0 candidateNameArray.1}", 326 | "count": 2, 327 | "source": [ 328 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 329 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 330 | ] 331 | }, 332 | { 333 | "value": "{newsTopic}", 334 | "count": 2, 335 | "source": [ 336 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js#L52", 337 | "https://github.com/wjohnson1000/wjohnson1000.github.io/blob/cb99bea35ebb38d6a246fd1da701d83550d769a5/scripts/main.js#L56" 338 | ] 339 | } 340 | ], 341 | "bestSources": null, 342 | "count": 7 343 | }, 344 | { 345 | "paramName": "q.enriched.url.title", 346 | "paramValues": [ 347 | { 348 | "value": "Asian Carp", 349 | "count": 2, 350 | "source": [ 351 | "https://github.com/sickle5stone/FishyBusiness/blob/230dd18dfdb1a167c3ab39390fc87374dd67d9c0/js/news.js#L64", 352 | "https://github.com/kongyujian/Fishackathon2016_Geospatial/blob/3eba2dd89c82761b7b11d32dc3b5817727ec7d27/js/news.js#L64" 353 | ] 354 | } 355 | ], 356 | "bestSources": null, 357 | "count": 2 358 | } 359 | ], 360 | "topPayloadParams": [ 361 | { 362 | "paramName": "end", 363 | "paramValues": [ 364 | { 365 | "value": "now", 366 | "count": 1, 367 | "source": [ 368 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 369 | ] 370 | } 371 | ], 372 | "bestSources": [ 373 | { 374 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 375 | "sourceId": 1 376 | } 377 | ], 378 | "count": 1 379 | }, 380 | { 381 | "paramName": "maxResults", 382 | "paramValues": [ 383 | { 384 | "value": "10", 385 | "count": 1, 386 | "source": [ 387 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 388 | ] 389 | } 390 | ], 391 | "bestSources": [ 392 | { 393 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 394 | "sourceId": 1 395 | } 396 | ], 397 | "count": 1 398 | }, 399 | { 400 | "paramName": "outputMode", 401 | "paramValues": [ 402 | { 403 | "value": "json", 404 | "count": 1, 405 | "source": [ 406 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 407 | ] 408 | } 409 | ], 410 | "bestSources": [ 411 | { 412 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 413 | "sourceId": 1 414 | } 415 | ], 416 | "count": 1 417 | }, 418 | { 419 | "paramName": "return", 420 | "paramValues": [ 421 | { 422 | "value": "enriched.url.title,enriched.url.url,enriched.url.author", 423 | "count": 1, 424 | "source": [ 425 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 426 | ] 427 | } 428 | ], 429 | "bestSources": [ 430 | { 431 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 432 | "sourceId": 1 433 | } 434 | ], 435 | "count": 1 436 | }, 437 | { 438 | "paramName": "start", 439 | "paramValues": [ 440 | { 441 | "value": "now-10d", 442 | "count": 1, 443 | "source": [ 444 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 445 | ] 446 | } 447 | ], 448 | "bestSources": [ 449 | { 450 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 451 | "sourceId": 1 452 | } 453 | ], 454 | "count": 1 455 | } 456 | ], 457 | "topJQueryAjaxParams": null, 458 | "topResponseFields": [ 459 | { 460 | "fieldName": "result.docs.length", 461 | "count": 5, 462 | "total": 26, 463 | "bestSources": [ 464 | { 465 | "url": "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 466 | "sourceId": 2 467 | }, 468 | { 469 | "url": "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414", 470 | "sourceId": 3 471 | } 472 | ], 473 | "source": [ 474 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/9e0731d8dde2fd5b7b3145ce25e7d598f8903903/Lab-3-Mashup%20Application/Source/js/app.js#L222", 475 | "https://github.com/cmoulika009/ASE-Lab-Assignments/blob/324ade52edd760d697ed597936265781412285f3/Lab-9-Cloud-Based-App-II/Source/Cloud%20App/js/app.js#L222", 476 | "https://github.com/ljm7b2/advSftwrEngnrTest/blob/dedd1afd4f0ddd52b9d1b94f8dce2cb0d5533de7/Source/LAB_5_MASHUP_SOURCE_CODE/lab_5_API_alchemyNEWS_SPOTIFY_playlists/app.js#L221", 477 | "https://github.com/FlyMoe/Candidus-Informatio/blob/4ecbac214df76e1493cfffc11ba45321a7543b30/assets/javascript/app.js#L414", 478 | "https://github.com/alexlcortes/another-test-repo/blob/c216a20deeec16d648256197df6bd2033131ffde/assets/javascript/app.js#L414" 479 | ] 480 | }, 481 | { 482 | "fieldName": "result.docs", 483 | "count": 1, 484 | "total": 26, 485 | "bestSources": [ 486 | { 487 | "url": "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47", 488 | "sourceId": 1 489 | } 490 | ], 491 | "source": [ 492 | "https://github.com/sfaries/AlchemyNews/blob/891a9ef358cc76e03d521d1569d5708134171732/js/alchemy.js#L47" 493 | ] 494 | } 495 | ] 496 | } 497 | } 498 | } 499 | }, 500 | "definitions": { 501 | "NewsResponse": { 502 | "type": "object", 503 | "properties": { 504 | "status": { "type": "string" }, 505 | "usage": { "type": "string" }, 506 | "totalTransactions": { "type": "string" }, 507 | "result": { 508 | "type": "object", 509 | "properties": { 510 | "docs": { 511 | "type": "array", 512 | "items": { 513 | "type": "object", 514 | "properties": { 515 | "id": { "type": "string" }, 516 | "source": { 517 | "type": "object", 518 | "properties": { 519 | "enriched": { 520 | "type": "object", 521 | "properties": { 522 | "url": { 523 | "type": "object", 524 | "properties": { "title": { "type": "string" } }, 525 | "required": ["title"] 526 | } 527 | }, 528 | "required": ["url"] 529 | } 530 | }, 531 | "required": ["enriched"] 532 | }, 533 | "timestamp": { "type": "integer" } 534 | }, 535 | "required": ["id", "source", "timestamp"] 536 | } 537 | }, 538 | "next": { "type": "string" }, 539 | "status": { "type": "string" } 540 | }, 541 | "required": ["docs", "next", "status"] 542 | } 543 | }, 544 | "required": ["status", "usage", "totalTransactions", "result"] 545 | } 546 | }, 547 | "x-apih-id": "ibm_watson_alchemy_data_news_api", 548 | "x-apih-ghusage": { 549 | "count": 0, 550 | "topUsages": [ 551 | { 552 | "repository": "likethecolor/Alchemy-API", 553 | "repoUrl": "https://github.com/likethecolor/Alchemy-API", 554 | "description": "Java client for the service provided by AlchemyAPI (a cloud-based text mining platform http://www.alchemyapi.com/)", 555 | "language": "Java", 556 | "stargazers": 9, 557 | "watchers": 9, 558 | "forks": 13, 559 | "subscribers": 3, 560 | "sources": [ 561 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/AbstractParserTest.java", 562 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/RelationsParserTest.java", 563 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/ConceptParserTest.java", 564 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/KeywordParserTest.java", 565 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/TaxonomyParserTest.java", 566 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/TaxonomiesParserTest.java", 567 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/NamedEntityParserTest.java", 568 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/entity/ResponseTest.java", 569 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/MicroformatParserTest.java", 570 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/LanguageParserTest.java", 571 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/entity/HeaderAlchemyEntityTest.java", 572 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/TitleParserTest.java", 573 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/AuthorParserTest.java", 574 | "https://github.com/likethecolor/Alchemy-API/blob/5208cfc92a878ceeaff052787af29da92d98db7e/src/test/java/com/likethecolor/alchemy/api/parser/json/SentimentParserTest.java", 575 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/AbstractParserTest.java", 576 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/RelationsParserTest.java", 577 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/KeywordParserTest.java", 578 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/ConceptParserTest.java", 579 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/TaxonomyParserTest.java", 580 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/TaxonomiesParserTest.java", 581 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/NamedEntityParserTest.java", 582 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/entity/ResponseTest.java", 583 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/MicroformatParserTest.java", 584 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/LanguageParserTest.java", 585 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/entity/HeaderAlchemyEntityTest.java", 586 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/TitleParserTest.java", 587 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/SentimentParserTest.java", 588 | "https://github.com/likethecolor/Alchemy-API/blob/ee054196b8a00fccd40e18748d9fa71aed540fef/src/test/java/com/likethecolor/alchemy/api/parser/json/AuthorParserTest.java" 589 | ] 590 | }, 591 | { 592 | "repository": "xiagu/plotlines", 593 | "repoUrl": "https://github.com/xiagu/plotlines", 594 | "description": "Generate a narrative chart for a well-known book or movie", 595 | "language": "HTML", 596 | "stargazers": 6, 597 | "watchers": 6, 598 | "forks": 2, 599 | "subscribers": 4, 600 | "sources": [ 601 | "https://github.com/xiagu/plotlines/blob/053f60b65e7fb95e701d71d5b61ff5efef2adf2d/data/mock.js" 602 | ] 603 | }, 604 | { 605 | "repository": "zemanel/HNMood", 606 | "repoUrl": "https://github.com/zemanel/HNMood", 607 | "description": null, 608 | "language": "Python", 609 | "stargazers": 4, 610 | "watchers": 4, 611 | "forks": 0, 612 | "subscribers": 1, 613 | "sources": [ 614 | "https://github.com/zemanel/HNMood/blob/bd6d1f230f8a612f665e334cd653afb59bc056b2/docs/alchemy_response.js" 615 | ] 616 | }, 617 | { 618 | "repository": "mollywhitnack/the-daily-feels", 619 | "repoUrl": "https://github.com/mollywhitnack/the-daily-feels", 620 | "description": null, 621 | "language": "JavaScript", 622 | "stargazers": 2, 623 | "watchers": 2, 624 | "forks": 2, 625 | "subscribers": 4, 626 | "sources": [ 627 | "https://github.com/mollywhitnack/the-daily-feels/blob/e5cb50c7ae82e04ab17e529584fb3ad023165c3f/src/api/mockNewsApi.js", 628 | "https://github.com/mollywhitnack/the-daily-feels/blob/74eb040adddc473d278921b94fbdbb566cd17882/src/api/mockNewsApi.js" 629 | ] 630 | }, 631 | { 632 | "repository": "wjohnson1000/Frontend_Personal_Project", 633 | "repoUrl": "https://github.com/wjohnson1000/Frontend_Personal_Project", 634 | "description": "Repo for g15 1st quarter project", 635 | "language": "JavaScript", 636 | "stargazers": 2, 637 | "watchers": 2, 638 | "forks": 0, 639 | "subscribers": 2, 640 | "sources": [ 641 | "https://github.com/wjohnson1000/Frontend_Personal_Project/blob/fd1244fae8a9932819ed287c6f53611b1acd6158/source/scripts/main.js" 642 | ] 643 | }, 644 | { 645 | "repository": "Soaring-Outliers/news_graph", 646 | "repoUrl": "https://github.com/Soaring-Outliers/news_graph", 647 | "description": "Graph gathering news", 648 | "language": "JavaScript", 649 | "stargazers": 1, 650 | "watchers": 1, 651 | "forks": 0, 652 | "subscribers": 1, 653 | "sources": [ 654 | "https://github.com/Soaring-Outliers/news_graph/blob/ae7cde461e49b6ee8fe932fcf6c581f3a5574da4/graph/models.py" 655 | ] 656 | }, 657 | { 658 | "repository": "collective/eea.alchemy", 659 | "repoUrl": "https://github.com/collective/eea.alchemy", 660 | "description": "Auto-discover geographical coverage, temporal coverage and keywords from documents common metadata (title, description, body, etc).", 661 | "language": "Python", 662 | "stargazers": 1, 663 | "watchers": 1, 664 | "forks": 1, 665 | "subscribers": 168, 666 | "sources": [ 667 | "https://github.com/collective/eea.alchemy/blob/6bf1ac036272423877639414d6e06fc55969d756/eea/alchemy/tests/fake.py", 668 | "https://github.com/collective/eea.alchemy/blob/25a833a7fa73024ad8cc2dd239b854a702348e59/eea/alchemy/tests/fake.py" 669 | ] 670 | }, 671 | { 672 | "repository": "ErikTillberg/SentimentVsStockPriceAnalyzer", 673 | "repoUrl": "https://github.com/ErikTillberg/SentimentVsStockPriceAnalyzer", 674 | "description": "Using Watson's text sentiment analysis to map twitter sentiment against stock prices", 675 | "language": "Python", 676 | "stargazers": 0, 677 | "watchers": 0, 678 | "forks": 0, 679 | "subscribers": 2, 680 | "sources": [ 681 | "https://github.com/ErikTillberg/SentimentVsStockPriceAnalyzer/blob/f7fbb1594bb0ecba9f983664e155c694694d759a/alchemy_sentiment.py", 682 | "https://github.com/ErikTillberg/SentimentVsStockPriceAnalyzer/blob/79db784d4d5f109c6bf0e4776b4244a2dec5f8a9/alchemy_sentiment.py" 683 | ] 684 | }, 685 | { 686 | "repository": "annaet/spotlight-news", 687 | "repoUrl": "https://github.com/annaet/spotlight-news", 688 | "description": null, 689 | "language": "JavaScript", 690 | "stargazers": 0, 691 | "watchers": 0, 692 | "forks": 0, 693 | "subscribers": 4, 694 | "sources": [ 695 | "https://github.com/annaet/spotlight-news/blob/05d43e011357ee32e87921e54bc9fbb4a4c77066/app/scripts/controllers/dendrogram.js" 696 | ] 697 | }, 698 | { 699 | "repository": "adalrsjr1/www", 700 | "repoUrl": "https://github.com/adalrsjr1/www", 701 | "description": null, 702 | "language": "PHP", 703 | "stargazers": 0, 704 | "watchers": 0, 705 | "forks": 0, 706 | "subscribers": 1, 707 | "sources": [ 708 | "https://github.com/adalrsjr1/www/blob/eaaf400107ba0cd03c678af076e66ec1d98f8326/ccbeu.com/ccbeu-perfil/AppCore.php" 709 | ] 710 | } 711 | ] 712 | }, 713 | "x-apih-relationships": [ 714 | { 715 | "relatedApiId": "ibm_watson_alchemy_language_api", 716 | "commonUsages": [ 717 | { 718 | "github_repo_name": "wjohnson1000/Frontend_Personal_Project", 719 | "stargazers_count": 2 720 | }, 721 | { 722 | "github_repo_name": "wjohnson1000/wjohnson1000.github.io", 723 | "stargazers_count": 0 724 | }, 725 | { "github_repo_name": "sfaries/AlchemyNews", "stargazers_count": 0 }, 726 | { 727 | "github_repo_name": "sickle5stone/FishyBusiness", 728 | "stargazers_count": 0 729 | }, 730 | { 731 | "github_repo_name": "kongyujian/Fishackathon2016_Geospatial", 732 | "stargazers_count": 0 733 | }, 734 | { 735 | "github_repo_name": "alexbtk/amos-ss16-proj9", 736 | "stargazers_count": 0 737 | }, 738 | { "github_repo_name": "Liux0047/watsonapp", "stargazers_count": 0 }, 739 | { 740 | "github_repo_name": "ljm7b2/advSftwrEngnrTest", 741 | "stargazers_count": 0 742 | }, 743 | { 744 | "github_repo_name": "cmoulika009/ASE-Lab-Assignments", 745 | "stargazers_count": 0 746 | }, 747 | { 748 | "github_repo_name": "FlyMoe/Candidus-Informatio", 749 | "stargazers_count": 0 750 | }, 751 | { 752 | "github_repo_name": "alexlcortes/another-test-repo", 753 | "stargazers_count": 0 754 | } 755 | ] 756 | }, 757 | { 758 | "relatedApiId": "ibm_watson_alchemy_vision_api", 759 | "commonUsages": [ 760 | { 761 | "github_repo_name": "wjohnson1000/Frontend_Personal_Project", 762 | "stargazers_count": 2 763 | }, 764 | { 765 | "github_repo_name": "wjohnson1000/wjohnson1000.github.io", 766 | "stargazers_count": 0 767 | }, 768 | { "github_repo_name": "sfaries/AlchemyNews", "stargazers_count": 0 }, 769 | { 770 | "github_repo_name": "sickle5stone/FishyBusiness", 771 | "stargazers_count": 0 772 | }, 773 | { 774 | "github_repo_name": "kongyujian/Fishackathon2016_Geospatial", 775 | "stargazers_count": 0 776 | }, 777 | { 778 | "github_repo_name": "alexbtk/amos-ss16-proj9", 779 | "stargazers_count": 0 780 | }, 781 | { "github_repo_name": "Liux0047/watsonapp", "stargazers_count": 0 }, 782 | { 783 | "github_repo_name": "ljm7b2/advSftwrEngnrTest", 784 | "stargazers_count": 0 785 | }, 786 | { 787 | "github_repo_name": "cmoulika009/ASE-Lab-Assignments", 788 | "stargazers_count": 0 789 | }, 790 | { 791 | "github_repo_name": "FlyMoe/Candidus-Informatio", 792 | "stargazers_count": 0 793 | }, 794 | { 795 | "github_repo_name": "alexlcortes/another-test-repo", 796 | "stargazers_count": 0 797 | } 798 | ] 799 | }, 800 | { 801 | "relatedApiId": "yahoo_weather_api", 802 | "commonUsages": [ 803 | { 804 | "github_repo_name": "sickle5stone/FishyBusiness", 805 | "stargazers_count": 0 806 | }, 807 | { 808 | "github_repo_name": "kongyujian/Fishackathon2016_Geospatial", 809 | "stargazers_count": 0 810 | } 811 | ] 812 | }, 813 | { 814 | "relatedApiId": "google_civic_info_api", 815 | "commonUsages": [ 816 | { 817 | "github_repo_name": "FlyMoe/Candidus-Informatio", 818 | "stargazers_count": 0 819 | }, 820 | { 821 | "github_repo_name": "alexlcortes/another-test-repo", 822 | "stargazers_count": 0 823 | } 824 | ] 825 | }, 826 | { 827 | "relatedApiId": "google_civicinfo_api", 828 | "commonUsages": [ 829 | { 830 | "github_repo_name": "FlyMoe/Candidus-Informatio", 831 | "stargazers_count": 0 832 | }, 833 | { 834 | "github_repo_name": "alexlcortes/another-test-repo", 835 | "stargazers_count": 0 836 | } 837 | ] 838 | }, 839 | { 840 | "relatedApiId": "google_blogger_api", 841 | "commonUsages": [ 842 | { 843 | "github_repo_name": "atrijitdasgupta/streetbuzz-investor", 844 | "stargazers_count": 0 845 | } 846 | ] 847 | }, 848 | { 849 | "relatedApiId": "amazon_product_advertising_api", 850 | "commonUsages": [ 851 | { 852 | "github_repo_name": "atrijitdasgupta/streetbuzz-investor", 853 | "stargazers_count": 0 854 | } 855 | ] 856 | }, 857 | { 858 | "relatedApiId": "quizlet_api_v2", 859 | "commonUsages": [ 860 | { "github_repo_name": "jaxball/hackthenorth16", "stargazers_count": 0 } 861 | ] 862 | } 863 | ], 864 | "x-apih-sdks": [ 865 | { 866 | "name": "rest-api-client", 867 | "downloads": { "last-day": 0, "last-month": 100, "last-week": 26 }, 868 | "description": "Simple REST client built on the request module", 869 | "url": "https://www.npmjs.com/package/rest-api-client", 870 | "repoUrl": "https://github.com/ryanlelek/rest-api-client", 871 | "language": "JavaScript" 872 | }, 873 | { 874 | "language": "JavaScript", 875 | "description": "Node.js REST API client for Parse.com", 876 | "url": "https://www.npmjs.com/package/parse-rest-api", 877 | "name": "parse-rest-api", 878 | "downloads": { "last-day": 0, "last-month": 21, "last-week": 3 } 879 | }, 880 | { 881 | "name": "json-rest-api", 882 | "downloads": { "last-day": 0, "last-month": 106, "last-week": 16 }, 883 | "description": "A simple lightweight REST API that receives and responds to JSON HTTP requests, supports all verbs. Very simple.", 884 | "url": "https://www.npmjs.com/package/json-rest-api", 885 | "repoUrl": "git://github.com/stdarg/json-rest-api", 886 | "language": "JavaScript" 887 | }, 888 | { 889 | "name": "pimatic-rest-api", 890 | "downloads": { "last-day": 0, "last-month": 120, "last-week": 16 }, 891 | "description": "Provides a rest-api for the webinterface.", 892 | "url": "https://www.npmjs.com/package/pimatic-rest-api", 893 | "repoUrl": "git://github.com/pimatic/pimatic-rest-api", 894 | "language": "JavaScript" 895 | }, 896 | { 897 | "name": "keystone-rest-api", 898 | "downloads": { "last-day": 1, "last-month": 58, "last-week": 10 }, 899 | "description": "Creates a powerful Rest API based on Keystone Lists", 900 | "url": "https://www.npmjs.com/package/keystone-rest-api", 901 | "repoUrl": "git+https://github.com/sarriaroman/Keystone-Rest-API", 902 | "language": "JavaScript", 903 | "license": "ISC" 904 | }, 905 | { 906 | "name": "sails-hook-cti-rest-api-responses", 907 | "downloads": { "last-day": 0, "last-month": 26, "last-week": 6 }, 908 | "description": "REST friendly api responses for sails", 909 | "url": "https://www.npmjs.com/package/sails-hook-cti-rest-api-responses", 910 | "repoUrl": "git+https://github.com/CanTireInnovations/sails-hook-cti-rest-api-responses", 911 | "language": "JavaScript", 912 | "license": "ISC" 913 | }, 914 | { 915 | "name": "ember-cli-rest-api-blueprint", 916 | "downloads": { "last-day": 2, "last-month": 274, "last-week": 59 }, 917 | "description": "Ember CLI blueprint addon for a DS.RESTAdapter compatible REST API", 918 | "url": "https://www.npmjs.com/package/ember-cli-rest-api-blueprint", 919 | "repoUrl": "git://github.com/manuelmitasch/ember-cli-rest-api-blueprint", 920 | "language": "JavaScript", 921 | "license": "MIT" 922 | }, 923 | { 924 | "name": "pulsar-rest-api-client-node", 925 | "downloads": { "last-day": 0, "last-month": 97, "last-week": 10 }, 926 | "description": "pulsar-rest-api-client-node [![Build Status](https://travis-ci.org/cargomedia/pulsar-rest-api-client-node.svg?branch=master)](https://travis-ci.org/cargomedia/pulsar-rest-api-client-node) ===========================", 927 | "url": "https://www.npmjs.com/package/pulsar-rest-api-client-node", 928 | "repoUrl": "git+ssh://git@github.com/cargomedia/pulsar-rest-api-client-node", 929 | "language": "JavaScript", 930 | "license": "MIT" 931 | }, 932 | { 933 | "name": "pulsar-rest-api", 934 | "downloads": { "last-day": 0, "last-month": 160, "last-week": 22 }, 935 | "description": "REST API for executing Pulsar tasks.", 936 | "url": "https://www.npmjs.com/package/pulsar-rest-api", 937 | "repoUrl": "git+ssh://git@github.com/cargomedia/pulsar-rest-api", 938 | "language": "JavaScript", 939 | "license": "MIT" 940 | }, 941 | { 942 | "name": "git-rest-api", 943 | "downloads": { "last-day": 1, "last-month": 137, "last-week": 27 }, 944 | "description": "A library providing a restful Git API mimicking as most as possible the old good git", 945 | "url": "https://www.npmjs.com/package/git-rest-api", 946 | "repoUrl": "https://github.com/korya/node-git-rest-api", 947 | "language": "JavaScript" 948 | } 949 | ], 950 | "x-apih-organization": "public", 951 | "meta": { "revision": 0, "created": 1495048571337, "version": 0 }, 952 | "$loki": 479 953 | } 954 | -------------------------------------------------------------------------------- /test/multiple_request_content.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "patch": { 26 | "description": "Creates a new pet in the store. Duplicates are allowed", 27 | "operationId": "addPet", 28 | "requestBody": { 29 | "content": { 30 | "application/json": { 31 | "schema": { 32 | "$ref": "#/components/schemas/ModifyPet" 33 | } 34 | }, 35 | "multipart/form-data": { 36 | "schema": { 37 | "$ref": "#/components/schemas/ModifyPetFile" 38 | } 39 | } 40 | } 41 | }, 42 | "responses": { 43 | "200": { 44 | "description": "pet response", 45 | "content": { 46 | "application/json": { 47 | "schema": { 48 | "$ref": "#/components/schemas/Pet" 49 | } 50 | } 51 | } 52 | }, 53 | "default": { 54 | "description": "unexpected error", 55 | "content": { 56 | "application/json": { 57 | "schema": { 58 | "$ref": "#/components/schemas/Error" 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | }, 67 | "components": { 68 | "schemas": { 69 | "ModifyPetFile": { 70 | "properties": { 71 | "pet[name]": { 72 | "type": "string" 73 | }, 74 | "pet[tag]": { 75 | "type": "string" 76 | }, 77 | "pet[picture]": { 78 | "type": "string" 79 | } 80 | } 81 | }, 82 | "ModifyPet": { 83 | "properties": { 84 | "name": { 85 | "type": "string" 86 | }, 87 | "tag": { 88 | "type": "string" 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/parameter_example_swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "get": { 26 | "description": "Get Pets from store", 27 | "operationId": "getPet", 28 | "parameters": [ 29 | { 30 | "name": "tags", 31 | "in": "query", 32 | "description": "tags to filter by", 33 | "required": false, 34 | "style": "form", 35 | "explode": false, 36 | "example": ["dog", "cat"], 37 | "schema": { 38 | "type": "array", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | }, 44 | { 45 | "name": "limit", 46 | "in": "query", 47 | "description": "maximum number of results to return", 48 | "example": 10, 49 | "required": false, 50 | "schema": { 51 | "type": "integer", 52 | "format": "int32" 53 | } 54 | } 55 | ], 56 | "responses": { 57 | "200": { 58 | "description": "pet response", 59 | "content": { 60 | "application/json": { 61 | "schema": { 62 | "$ref": "#/components/schemas/Pet" 63 | } 64 | } 65 | } 66 | }, 67 | "default": { 68 | "description": "unexpected error", 69 | "content": { 70 | "application/json": { 71 | "schema": { 72 | "$ref": "#/components/schemas/Error" 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | }, 80 | "/animals": { 81 | "parameters": [ 82 | { 83 | "name": "tags", 84 | "in": "query", 85 | "description": "tags to filter by", 86 | "required": false, 87 | "style": "form", 88 | "explode": false, 89 | "example": ["dog", "cat"], 90 | "schema": { 91 | "type": "array", 92 | "items": { 93 | "type": "string" 94 | } 95 | } 96 | }, 97 | { 98 | "name": "limit", 99 | "in": "query", 100 | "description": "maximum number of results to return", 101 | "example": 10, 102 | "required": false, 103 | "schema": { 104 | "type": "integer", 105 | "format": "int32" 106 | } 107 | } 108 | ], 109 | "get": { 110 | "description": "Get Pets from store", 111 | "operationId": "getPet", 112 | "responses": { 113 | "200": { 114 | "description": "pet response", 115 | "content": { 116 | "application/json": { 117 | "schema": { 118 | "$ref": "#/components/schemas/Pet" 119 | } 120 | } 121 | } 122 | }, 123 | "default": { 124 | "description": "unexpected error", 125 | "content": { 126 | "application/json": { 127 | "schema": { 128 | "$ref": "#/components/schemas/Error" 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | }, 136 | "/species": { 137 | "parameters": [ 138 | { 139 | "name": "id", 140 | "in": "query", 141 | "description": "the species id", 142 | "required": false, 143 | "example": 1, 144 | "schema": { 145 | "type": "integer" 146 | } 147 | } 148 | ], 149 | "get": { 150 | "description": "Get Pets from store", 151 | "operationId": "getPet", 152 | "parameters": [ 153 | { 154 | "name": "id", 155 | "in": "query", 156 | "description": "A comma-seperated list of species IDs", 157 | "required": false, 158 | "explode": false, 159 | "example": [1, 2], 160 | "schema": { 161 | "type": "array", 162 | "items": { 163 | "type": "integer" 164 | } 165 | } 166 | } 167 | ], 168 | "responses": { 169 | "200": { 170 | "description": "pet response", 171 | "content": { 172 | "application/json": { 173 | "schema": { 174 | "$ref": "#/components/schemas/Species" 175 | } 176 | } 177 | } 178 | }, 179 | "default": { 180 | "description": "unexpected error", 181 | "content": { 182 | "application/json": { 183 | "schema": { 184 | "$ref": "#/components/schemas/Error" 185 | } 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | }, 193 | "components": { 194 | "schemas": { 195 | "Pet": { 196 | "allOf": [ 197 | { 198 | "$ref": "#/components/schemas/NewPet" 199 | }, 200 | { 201 | "required": ["id"], 202 | "properties": { 203 | "id": { 204 | "type": "integer", 205 | "format": "int64" 206 | } 207 | } 208 | } 209 | ] 210 | }, 211 | "NewPet": { 212 | "required": ["name"], 213 | "properties": { 214 | "name": { 215 | "type": "string" 216 | }, 217 | "tag": { 218 | "type": "string" 219 | } 220 | } 221 | }, 222 | "Species": { 223 | "items": { 224 | "$ref": "#/components/thing" 225 | }, 226 | "type": "array" 227 | }, 228 | "Thing": { 229 | "required": ["id"], 230 | "properties": { 231 | "id": { 232 | "type": "integer" 233 | } 234 | } 235 | }, 236 | "Error": { 237 | "required": ["code", "message"], 238 | "properties": { 239 | "code": { 240 | "type": "integer", 241 | "format": "int32" 242 | }, 243 | "message": { 244 | "type": "string" 245 | } 246 | } 247 | } 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /test/parameter_schema_reference.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "post": { 26 | "description": "Creates a new pet in the store. Duplicates are allowed", 27 | "operationId": "addPet", 28 | "parameters": [ 29 | { 30 | "in": "query", 31 | "name": "pet", 32 | "description": "Pet to add to the store", 33 | "schema": { 34 | "$ref": "#/components/schemas/NewPet" 35 | } 36 | } 37 | ], 38 | "responses": { 39 | "200": { 40 | "description": "pet response", 41 | "content": { 42 | "application/json": { 43 | "schema": { 44 | "$ref": "#/components/schemas/Pet" 45 | } 46 | } 47 | } 48 | }, 49 | "default": { 50 | "description": "unexpected error", 51 | "content": { 52 | "application/json": { 53 | "schema": { 54 | "$ref": "#/components/schemas/Error" 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | }, 63 | "components": { 64 | "schemas": { 65 | "NewPet": { 66 | "required": ["name"], 67 | "properties": { 68 | "name": { 69 | "type": "string" 70 | }, 71 | "tag": { 72 | "type": "string" 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/parameter_variations_swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "get": { 26 | "description": "Get Pets from store", 27 | "operationId": "getPet", 28 | "parameters": [ 29 | { 30 | "name": "id", 31 | "in": "query", 32 | "explode": false, 33 | "example": { 34 | "role": "admin", 35 | "firstName": "Alex", 36 | "age": 34 37 | }, 38 | "schema": { 39 | "type": "object" 40 | } 41 | }, 42 | { 43 | "name": "tags", 44 | "in": "query", 45 | "description": "tags to filter by", 46 | "required": false, 47 | "style": "form", 48 | "explode": false, 49 | "example": [ 50 | "dog", 51 | "cat" 52 | ], 53 | "schema": { 54 | "type": "array", 55 | "items": { 56 | "type": "string" 57 | } 58 | } 59 | }, 60 | { 61 | "name": "limit", 62 | "in": "query", 63 | "description": "maximum number of results to return", 64 | "example": 10, 65 | "required": false, 66 | "schema": { 67 | "type": "integer", 68 | "format": "int32" 69 | } 70 | } 71 | ], 72 | "responses": { 73 | "200": { 74 | "description": "pet response", 75 | "content": { 76 | "application/json": { 77 | "schema": { 78 | "$ref": "#/components/schemas/Pet" 79 | } 80 | } 81 | } 82 | }, 83 | "default": { 84 | "description": "unexpected error", 85 | "content": { 86 | "application/json": { 87 | "schema": { 88 | "$ref": "#/components/schemas/Error" 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | }, 96 | "/pets/{id}": { 97 | "parameters": [ 98 | { 99 | "name": "id", 100 | "in": "path", 101 | "explode": false, 102 | "schema": { 103 | "type": "integer" 104 | } 105 | }, 106 | { 107 | "name": "X-MYHEADER", 108 | "in": "header", 109 | "schema": { 110 | "type": "string" 111 | } 112 | } 113 | ], 114 | "get": { 115 | "description": "Get Pets from store", 116 | "operationId": "getPet", 117 | "parameters": [ 118 | { 119 | "name": "id", 120 | "in": "path", 121 | "explode": false, 122 | "example": { 123 | "role": "admin", 124 | "firstName": "Alex", 125 | "age": 34 126 | }, 127 | "schema": { 128 | "type": "object" 129 | } 130 | }, 131 | { 132 | "name": "X-MYHEADER", 133 | "in": "header", 134 | "schema": { 135 | "type": "string" 136 | } 137 | }, 138 | { 139 | "name": "tags", 140 | "in": "query", 141 | "description": "tags to filter by", 142 | "required": false, 143 | "style": "form", 144 | "explode": false, 145 | "example": [ 146 | "dog", 147 | "cat" 148 | ], 149 | "schema": { 150 | "type": "array", 151 | "items": { 152 | "type": "string" 153 | } 154 | } 155 | }, 156 | { 157 | "name": "limit", 158 | "in": "query", 159 | "description": "maximum number of results to return", 160 | "example": 10, 161 | "required": false, 162 | "schema": { 163 | "type": "integer", 164 | "format": "int32" 165 | } 166 | } 167 | ], 168 | "responses": { 169 | "200": { 170 | "description": "pet response", 171 | "content": { 172 | "application/json": { 173 | "schema": { 174 | "$ref": "#/components/schemas/Pet" 175 | } 176 | } 177 | } 178 | }, 179 | "default": { 180 | "description": "unexpected error", 181 | "content": { 182 | "application/json": { 183 | "schema": { 184 | "$ref": "#/components/schemas/Error" 185 | } 186 | } 187 | } 188 | } 189 | } 190 | } 191 | }, 192 | "/animals": { 193 | "parameters": [ 194 | { 195 | "name": "tags", 196 | "in": "query", 197 | "description": "tags to filter by", 198 | "required": false, 199 | "style": "form", 200 | "explode": false, 201 | "examples": { 202 | "firstExample": { 203 | "$ref": "#/components/examples/firstExample" 204 | } 205 | }, 206 | "schema": { 207 | "type": "array", 208 | "items": { 209 | "type": "string" 210 | } 211 | } 212 | }, 213 | { 214 | "name": "limit", 215 | "in": "query", 216 | "description": "maximum number of results to return", 217 | "example": 10, 218 | "required": false, 219 | "schema": { 220 | "type": "integer", 221 | "format": "int32" 222 | } 223 | } 224 | ], 225 | "get": { 226 | "description": "Get Pets from store", 227 | "operationId": "getPet", 228 | "responses": { 229 | "200": { 230 | "description": "pet response", 231 | "content": { 232 | "application/json": { 233 | "schema": { 234 | "$ref": "#/components/schemas/Pet" 235 | } 236 | } 237 | } 238 | }, 239 | "default": { 240 | "description": "unexpected error", 241 | "content": { 242 | "application/json": { 243 | "schema": { 244 | "$ref": "#/components/schemas/Error" 245 | } 246 | } 247 | } 248 | } 249 | } 250 | } 251 | }, 252 | "/species": { 253 | "parameters": [ 254 | { 255 | "name": "id", 256 | "in": "query", 257 | "description": "the species id", 258 | "required": false, 259 | "example": 1, 260 | "schema": { 261 | "type": "integer" 262 | } 263 | } 264 | ], 265 | "get": { 266 | "description": "Get Pets from store", 267 | "operationId": "getPet", 268 | "parameters": [ 269 | { 270 | "name": "id", 271 | "in": "query", 272 | "description": "A comma-seperated list of species IDs", 273 | "required": false, 274 | "explode": false, 275 | "example": [ 276 | 1, 277 | 2 278 | ], 279 | "schema": { 280 | "type": "array", 281 | "items": { 282 | "type": "integer" 283 | } 284 | } 285 | } 286 | ], 287 | "responses": { 288 | "200": { 289 | "description": "pet response", 290 | "content": { 291 | "application/json": { 292 | "schema": { 293 | "$ref": "#/components/schemas/Species" 294 | } 295 | } 296 | } 297 | }, 298 | "default": { 299 | "description": "unexpected error", 300 | "content": { 301 | "application/json": { 302 | "schema": { 303 | "$ref": "#/components/schemas/Error" 304 | } 305 | } 306 | } 307 | } 308 | } 309 | } 310 | } 311 | }, 312 | "components": { 313 | "examples": { 314 | "firstExample": { 315 | "summary": "A first example", 316 | "value": [ 317 | "dog", 318 | "cat" 319 | ] 320 | } 321 | }, 322 | "schemas": { 323 | "Pet": { 324 | "allOf": [ 325 | { 326 | "$ref": "#/components/schemas/NewPet" 327 | }, 328 | { 329 | "required": [ 330 | "id" 331 | ], 332 | "properties": { 333 | "id": { 334 | "type": "integer", 335 | "format": "int64" 336 | } 337 | } 338 | } 339 | ] 340 | }, 341 | "NewPet": { 342 | "required": [ 343 | "name" 344 | ], 345 | "properties": { 346 | "name": { 347 | "type": "string" 348 | }, 349 | "tag": { 350 | "type": "string" 351 | } 352 | } 353 | }, 354 | "Species": { 355 | "items": { 356 | "$ref": "#/components/thing" 357 | }, 358 | "type": "array" 359 | }, 360 | "Thing": { 361 | "required": [ 362 | "id" 363 | ], 364 | "properties": { 365 | "id": { 366 | "type": "integer" 367 | } 368 | } 369 | }, 370 | "Error": { 371 | "required": [ 372 | "code", 373 | "message" 374 | ], 375 | "properties": { 376 | "code": { 377 | "type": "integer", 378 | "format": "int32" 379 | }, 380 | "message": { 381 | "type": "string" 382 | } 383 | } 384 | } 385 | } 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /test/petstore_oas.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "version": "1.0.0", 5 | "title": "Swagger Petstore", 6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "name": "Swagger API Team", 10 | "email": "apiteam@swagger.io", 11 | "url": "http://swagger.io" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 16 | } 17 | }, 18 | "servers": [ 19 | { 20 | "url": "http://petstore.swagger.io/api" 21 | } 22 | ], 23 | "paths": { 24 | "/pets": { 25 | "servers": [ 26 | { 27 | "url": "https://path-override.example.com" 28 | } 29 | ], 30 | "get": { 31 | "servers": [ 32 | { 33 | "url": "https://method-override.example.com" 34 | } 35 | ], 36 | "description": "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n", 37 | "operationId": "findPets", 38 | "parameters": [ 39 | { 40 | "name": "tags", 41 | "in": "query", 42 | "description": "tags to filter by", 43 | "required": false, 44 | "style": "form", 45 | "schema": { 46 | "type": "array", 47 | "items": { 48 | "type": "string" 49 | } 50 | } 51 | }, 52 | { 53 | "name": "limit", 54 | "in": "query", 55 | "description": "maximum number of results to return", 56 | "required": false, 57 | "schema": { 58 | "type": "integer", 59 | "format": "int32" 60 | } 61 | } 62 | ], 63 | "responses": { 64 | "200": { 65 | "description": "pet response", 66 | "content": { 67 | "application/json": { 68 | "schema": { 69 | "type": "array", 70 | "items": { 71 | "$ref": "#/components/schemas/Pet" 72 | } 73 | } 74 | } 75 | } 76 | }, 77 | "default": { 78 | "description": "unexpected error", 79 | "content": { 80 | "application/json": { 81 | "schema": { 82 | "$ref": "#/components/schemas/Error" 83 | } 84 | } 85 | } 86 | } 87 | } 88 | }, 89 | "post": { 90 | "description": "Creates a new pet in the store. Duplicates are allowed", 91 | "operationId": "addPet", 92 | "requestBody": { 93 | "description": "Pet to add to the store", 94 | "required": true, 95 | "content": { 96 | "application/json": { 97 | "schema": { 98 | "$ref": "#/components/schemas/NewPet" 99 | } 100 | } 101 | } 102 | }, 103 | "responses": { 104 | "200": { 105 | "description": "pet response", 106 | "content": { 107 | "application/json": { 108 | "schema": { 109 | "$ref": "#/components/schemas/Pet" 110 | } 111 | } 112 | } 113 | }, 114 | "default": { 115 | "description": "unexpected error", 116 | "content": { 117 | "application/json": { 118 | "schema": { 119 | "$ref": "#/components/schemas/Error" 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | }, 127 | "/pets/{id}": { 128 | "get": { 129 | "description": "Returns a user based on a single ID, if the user does not have access to the pet", 130 | "operationId": "find pet by id", 131 | "parameters": [ 132 | { 133 | "name": "id", 134 | "in": "path", 135 | "description": "ID of pet to fetch", 136 | "required": true, 137 | "schema": { 138 | "type": "integer", 139 | "format": "int64" 140 | } 141 | } 142 | ], 143 | "responses": { 144 | "200": { 145 | "description": "pet response", 146 | "content": { 147 | "application/json": { 148 | "schema": { 149 | "$ref": "#/components/schemas/Pet" 150 | } 151 | } 152 | } 153 | }, 154 | "default": { 155 | "description": "unexpected error", 156 | "content": { 157 | "application/json": { 158 | "schema": { 159 | "$ref": "#/components/schemas/Error" 160 | } 161 | } 162 | } 163 | } 164 | } 165 | }, 166 | "delete": { 167 | "description": "deletes a single pet based on the ID supplied", 168 | "operationId": "deletePet", 169 | "parameters": [ 170 | { 171 | "name": "id", 172 | "in": "path", 173 | "description": "ID of pet to delete", 174 | "required": true, 175 | "schema": { 176 | "type": "integer", 177 | "format": "int64" 178 | } 179 | } 180 | ], 181 | "responses": { 182 | "204": { 183 | "description": "pet deleted" 184 | }, 185 | "default": { 186 | "description": "unexpected error", 187 | "content": { 188 | "application/json": { 189 | "schema": { 190 | "$ref": "#/components/schemas/Error" 191 | } 192 | } 193 | } 194 | } 195 | } 196 | } 197 | } 198 | }, 199 | "components": { 200 | "schemas": { 201 | "Pet": { 202 | "allOf": [ 203 | { 204 | "$ref": "#/components/schemas/NewPet" 205 | }, 206 | { 207 | "required": ["id"], 208 | "properties": { 209 | "id": { 210 | "type": "integer", 211 | "format": "int64" 212 | } 213 | } 214 | } 215 | ] 216 | }, 217 | "NewPet": { 218 | "required": ["name"], 219 | "properties": { 220 | "name": { 221 | "type": "string" 222 | }, 223 | "tag": { 224 | "type": "string" 225 | } 226 | } 227 | }, 228 | "Error": { 229 | "required": ["code", "message"], 230 | "properties": { 231 | "code": { 232 | "type": "integer", 233 | "format": "int32" 234 | }, 235 | "message": { 236 | "type": "string" 237 | } 238 | } 239 | } 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /test/petstore_swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "schemes": ["http", "https"], 4 | "host": "petstore.swagger.io", 5 | "basePath": "/v2", 6 | "info": { 7 | "description": "This is a sample server Petstore server.\nYou can find out more about Swagger at\n[http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).\nFor this sample, you can use the api key `special-key` to test the authorization filters.\n# Introduction\nThis API is documented in **OpenAPI format** and is based on\n[Petstore sample](http://petstore.swagger.io/) provided by [swagger.io](http://swagger.io) team.\nIt was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo)\ntool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard\nOpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md).\n# OpenAPI Specification\nThis API is documented in **OpenAPI format** and is based on\n[Petstore sample](http://petstore.swagger.io/) provided by [swagger.io](http://swagger.io) team.\nIt was **extended** to illustrate features of [generator-openapi-repo](https://github.com/Rebilly/generator-openapi-repo)\ntool and [ReDoc](https://github.com/Rebilly/ReDoc) documentation. In addition to standard\nOpenAPI syntax we use a few [vendor extensions](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md).\n# Cross-Origin Resource Sharing\nThis API features Cross-Origin Resource Sharing (CORS) implemented in compliance with [W3C spec](https://www.w3.org/TR/cors/).\nAnd that allows cross-domain communication from the browser.\nAll responses have a wildcard same-origin which makes them completely public and accessible to everyone, including any code on any site.\n# Authentication\nPetstore offers two forms of authentication:\n - API Key\n - OAuth2\n\nOAuth2 - an open protocol to allow secure authorization in a simple\nand standard method from web, mobile and desktop applications.\n\n", 8 | "version": "1.0.0", 9 | "title": "Swagger Petstore", 10 | "termsOfService": "http://swagger.io/terms/", 11 | "contact": { 12 | "email": "apiteam@swagger.io", 13 | "url": "https://github.com/Rebilly/ReDoc" 14 | }, 15 | "x-logo": { 16 | "url": "https://rebilly.github.io/ReDoc/petstore-logo.png" 17 | }, 18 | "license": { 19 | "name": "Apache 2.0", 20 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 21 | } 22 | }, 23 | "externalDocs": { 24 | "description": "Find out how to create Github repo for your OpenAPI spec.", 25 | "url": "https://github.com/Rebilly/generator-openapi-repo" 26 | }, 27 | "tags": [ 28 | { 29 | "name": "pet", 30 | "description": "Everything about your Pets" 31 | }, 32 | { 33 | "name": "store", 34 | "description": "Access to Petstore orders" 35 | }, 36 | { 37 | "name": "user", 38 | "description": "Operations about user" 39 | } 40 | ], 41 | "x-tagGroups": [ 42 | { 43 | "name": "General", 44 | "tags": ["pet", "store"] 45 | }, 46 | { 47 | "name": "User Management", 48 | "tags": ["user"] 49 | } 50 | ], 51 | "securityDefinitions": { 52 | "petstore_auth": { 53 | "description": "Get access to data while protecting your account credentials.\nOAuth2 is also a safer and more secure way to give you access.\n", 54 | "type": "oauth2", 55 | "authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog", 56 | "flow": "implicit", 57 | "scopes": { 58 | "write:pets": "modify pets in your account", 59 | "read:pets": "read your pets" 60 | } 61 | }, 62 | "api_key": { 63 | "description": "For this sample, you can use the api key `special-key` to test the authorization filters.\n", 64 | "type": "apiKey", 65 | "name": "api_key", 66 | "in": "header" 67 | } 68 | }, 69 | "x-servers": [ 70 | { 71 | "url": "//petstore.swagger.io/v2", 72 | "description": "Default server" 73 | }, 74 | { 75 | "url": "//petstore.swagger.io/sandbox", 76 | "description": "Sandbox server" 77 | } 78 | ], 79 | "paths": { 80 | "/pet": { 81 | "post": { 82 | "tags": ["pet"], 83 | "summary": "Add a new pet to the store", 84 | "description": "Add new pet to the store inventory.", 85 | "operationId": "addPet", 86 | "consumes": ["application/json", "application/xml"], 87 | "produces": ["application/xml", "application/json"], 88 | "parameters": [ 89 | { 90 | "in": "body", 91 | "name": "body", 92 | "description": "Pet object that needs to be added to the store", 93 | "required": true, 94 | "schema": { 95 | "$ref": "#/definitions/Pet" 96 | } 97 | } 98 | ], 99 | "responses": { 100 | "405": { 101 | "description": "Invalid input" 102 | } 103 | }, 104 | "security": [ 105 | { 106 | "petstore_auth": ["write:pets", "read:pets"] 107 | } 108 | ], 109 | "x-code-samples": [ 110 | { 111 | "lang": "C#", 112 | "source": "PetStore.v1.Pet pet = new PetStore.v1.Pet();\npet.setApiKey(\"your api key\");\npet.petType = PetStore.v1.Pet.TYPE_DOG;\npet.name = \"Rex\";\n// set other fields\nPetStoreResponse response = pet.create();\nif (response.statusCode == HttpStatusCode.Created)\n{\n // Successfully created\n}\nelse\n{\n // Something wrong -- check response for errors\n Console.WriteLine(response.getRawResponse());\n}\n" 113 | }, 114 | { 115 | "lang": "PHP", 116 | "source": "$form = new \\PetStore\\Entities\\Pet();\n$form->setPetType(\"Dog\");\n$form->setName(\"Rex\");\n// set other fields\ntry {\n $pet = $client->pets()->create($form);\n} catch (UnprocessableEntityException $e) {\n var_dump($e->getErrors());\n}\n" 117 | } 118 | ] 119 | }, 120 | "put": { 121 | "tags": ["pet"], 122 | "summary": "Update an existing pet", 123 | "description": "", 124 | "operationId": "updatePet", 125 | "consumes": ["application/json", "application/xml"], 126 | "produces": ["application/xml", "application/json"], 127 | "parameters": [ 128 | { 129 | "in": "body", 130 | "name": "body", 131 | "description": "Pet object that needs to be added to the store", 132 | "required": true, 133 | "schema": { 134 | "$ref": "#/definitions/Pet" 135 | } 136 | } 137 | ], 138 | "responses": { 139 | "400": { 140 | "description": "Invalid ID supplied" 141 | }, 142 | "404": { 143 | "description": "Pet not found" 144 | }, 145 | "405": { 146 | "description": "Validation exception" 147 | } 148 | }, 149 | "security": [ 150 | { 151 | "petstore_auth": ["write:pets", "read:pets"] 152 | } 153 | ], 154 | "x-code-samples": [ 155 | { 156 | "lang": "PHP", 157 | "source": "$form = new \\PetStore\\Entities\\Pet();\n$form->setPetId(1);\n$form->setPetType(\"Dog\");\n$form->setName(\"Rex\");\n// set other fields\ntry {\n $pet = $client->pets()->update($form);\n} catch (UnprocessableEntityException $e) {\n var_dump($e->getErrors());\n}\n" 158 | } 159 | ] 160 | } 161 | }, 162 | "/pet/{petId}": { 163 | "get": { 164 | "tags": ["pet"], 165 | "summary": "Find pet by ID", 166 | "description": "Returns a single pet", 167 | "operationId": "getPetById", 168 | "produces": ["application/xml", "application/json"], 169 | "parameters": [ 170 | { 171 | "name": "petId", 172 | "in": "path", 173 | "description": "ID of pet to return", 174 | "required": true, 175 | "type": "integer", 176 | "format": "int64" 177 | } 178 | ], 179 | "responses": { 180 | "200": { 181 | "description": "successful operation", 182 | "schema": { 183 | "$ref": "#/definitions/Pet" 184 | } 185 | }, 186 | "400": { 187 | "description": "Invalid ID supplied" 188 | }, 189 | "404": { 190 | "description": "Pet not found" 191 | } 192 | }, 193 | "security": [ 194 | { 195 | "api_key": [] 196 | } 197 | ] 198 | }, 199 | "post": { 200 | "tags": ["pet"], 201 | "summary": "Updates a pet in the store with form data", 202 | "description": "", 203 | "operationId": "updatePetWithForm", 204 | "consumes": ["application/x-www-form-urlencoded"], 205 | "produces": ["application/xml", "application/json"], 206 | "parameters": [ 207 | { 208 | "name": "petId", 209 | "in": "path", 210 | "description": "ID of pet that needs to be updated", 211 | "required": true, 212 | "type": "integer", 213 | "format": "int64" 214 | }, 215 | { 216 | "name": "name", 217 | "in": "formData", 218 | "description": "Updated name of the pet", 219 | "required": false, 220 | "type": "string" 221 | }, 222 | { 223 | "name": "status", 224 | "in": "formData", 225 | "description": "Updated status of the pet", 226 | "required": false, 227 | "type": "string" 228 | } 229 | ], 230 | "responses": { 231 | "405": { 232 | "description": "Invalid input" 233 | } 234 | }, 235 | "security": [ 236 | { 237 | "petstore_auth": ["write:pets", "read:pets"] 238 | } 239 | ] 240 | }, 241 | "delete": { 242 | "tags": ["pet"], 243 | "summary": "Deletes a pet", 244 | "description": "", 245 | "operationId": "deletePet", 246 | "produces": ["application/xml", "application/json"], 247 | "parameters": [ 248 | { 249 | "name": "api_key", 250 | "in": "header", 251 | "required": false, 252 | "type": "string", 253 | "x-example": "Bearer " 254 | }, 255 | { 256 | "name": "petId", 257 | "in": "path", 258 | "description": "Pet id to delete", 259 | "required": true, 260 | "type": "integer", 261 | "format": "int64" 262 | } 263 | ], 264 | "responses": { 265 | "400": { 266 | "description": "Invalid pet value" 267 | } 268 | }, 269 | "security": [ 270 | { 271 | "petstore_auth": ["write:pets", "read:pets"] 272 | } 273 | ] 274 | } 275 | }, 276 | "/pet/{petId}/uploadImage": { 277 | "post": { 278 | "tags": ["pet"], 279 | "summary": "uploads an image", 280 | "description": "", 281 | "operationId": "uploadFile", 282 | "consumes": ["multipart/form-data"], 283 | "produces": ["application/json"], 284 | "parameters": [ 285 | { 286 | "name": "petId", 287 | "in": "path", 288 | "description": "ID of pet to update", 289 | "required": true, 290 | "type": "integer", 291 | "format": "int64" 292 | }, 293 | { 294 | "name": "additionalMetadata", 295 | "in": "formData", 296 | "description": "Additional data to pass to server", 297 | "required": false, 298 | "type": "string" 299 | }, 300 | { 301 | "name": "file", 302 | "in": "formData", 303 | "description": "file to upload", 304 | "required": false, 305 | "type": "file" 306 | } 307 | ], 308 | "responses": { 309 | "200": { 310 | "description": "successful operation", 311 | "schema": { 312 | "$ref": "#/definitions/ApiResponse" 313 | } 314 | } 315 | }, 316 | "security": [ 317 | { 318 | "petstore_auth": ["write:pets", "read:pets"] 319 | } 320 | ] 321 | } 322 | }, 323 | "/pet/findByStatus": { 324 | "get": { 325 | "tags": ["pet"], 326 | "summary": "Finds Pets by status", 327 | "description": "Multiple status values can be provided with comma separated strings", 328 | "operationId": "findPetsByStatus", 329 | "produces": ["application/xml", "application/json"], 330 | "parameters": [ 331 | { 332 | "name": "status", 333 | "in": "query", 334 | "description": "Status values that need to be considered for filter", 335 | "required": true, 336 | "type": "array", 337 | "items": { 338 | "type": "string", 339 | "enum": ["available", "pending", "sold"], 340 | "default": "available" 341 | }, 342 | "collectionFormat": "csv" 343 | } 344 | ], 345 | "responses": { 346 | "200": { 347 | "description": "successful operation", 348 | "schema": { 349 | "type": "array", 350 | "items": { 351 | "$ref": "#/definitions/Pet" 352 | } 353 | } 354 | }, 355 | "400": { 356 | "description": "Invalid status value" 357 | } 358 | }, 359 | "security": [ 360 | { 361 | "petstore_auth": ["write:pets", "read:pets"] 362 | } 363 | ] 364 | } 365 | }, 366 | "/pet/findByTags": { 367 | "get": { 368 | "tags": ["pet"], 369 | "summary": "Finds Pets by tags", 370 | "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", 371 | "operationId": "findPetsByTags", 372 | "deprecated": true, 373 | "produces": ["application/xml", "application/json"], 374 | "parameters": [ 375 | { 376 | "name": "tags", 377 | "in": "query", 378 | "description": "Tags to filter by", 379 | "required": true, 380 | "type": "array", 381 | "items": { 382 | "type": "string" 383 | }, 384 | "collectionFormat": "csv" 385 | } 386 | ], 387 | "responses": { 388 | "200": { 389 | "description": "successful operation", 390 | "schema": { 391 | "type": "array", 392 | "items": { 393 | "$ref": "#/definitions/Pet" 394 | } 395 | } 396 | }, 397 | "400": { 398 | "description": "Invalid tag value" 399 | } 400 | }, 401 | "security": [ 402 | { 403 | "petstore_auth": ["write:pets", "read:pets"] 404 | } 405 | ] 406 | } 407 | }, 408 | "/store/inventory": { 409 | "get": { 410 | "tags": ["store"], 411 | "summary": "Returns pet inventories by status", 412 | "description": "Returns a map of status codes to quantities", 413 | "operationId": "getInventory", 414 | "produces": ["application/json"], 415 | "parameters": [], 416 | "responses": { 417 | "200": { 418 | "description": "successful operation", 419 | "schema": { 420 | "type": "object", 421 | "additionalProperties": { 422 | "type": "integer", 423 | "format": "int32" 424 | } 425 | } 426 | } 427 | }, 428 | "security": [ 429 | { 430 | "api_key": [] 431 | } 432 | ] 433 | } 434 | }, 435 | "/store/order": { 436 | "post": { 437 | "tags": ["store"], 438 | "summary": "Place an order for a pet", 439 | "description": "", 440 | "operationId": "placeOrder", 441 | "produces": ["application/xml", "application/json"], 442 | "parameters": [ 443 | { 444 | "in": "body", 445 | "name": "body", 446 | "description": "order placed for purchasing the pet", 447 | "required": true, 448 | "schema": { 449 | "$ref": "#/definitions/Order" 450 | } 451 | } 452 | ], 453 | "responses": { 454 | "200": { 455 | "description": "successful operation", 456 | "schema": { 457 | "$ref": "#/definitions/Order" 458 | } 459 | }, 460 | "400": { 461 | "description": "Invalid Order" 462 | } 463 | } 464 | } 465 | }, 466 | "/store/order/{orderId}": { 467 | "get": { 468 | "tags": ["store"], 469 | "summary": "Find purchase order by ID", 470 | "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", 471 | "operationId": "getOrderById", 472 | "produces": ["application/xml", "application/json"], 473 | "parameters": [ 474 | { 475 | "name": "orderId", 476 | "in": "path", 477 | "description": "ID of pet that needs to be fetched", 478 | "required": true, 479 | "type": "integer", 480 | "maximum": 5, 481 | "minimum": 1, 482 | "format": "int64" 483 | } 484 | ], 485 | "responses": { 486 | "200": { 487 | "description": "successful operation", 488 | "schema": { 489 | "$ref": "#/definitions/Order" 490 | } 491 | }, 492 | "400": { 493 | "description": "Invalid ID supplied" 494 | }, 495 | "404": { 496 | "description": "Order not found" 497 | } 498 | } 499 | }, 500 | "delete": { 501 | "tags": ["store"], 502 | "summary": "Delete purchase order by ID", 503 | "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", 504 | "operationId": "deleteOrder", 505 | "produces": ["application/xml", "application/json"], 506 | "parameters": [ 507 | { 508 | "name": "orderId", 509 | "in": "path", 510 | "description": "ID of the order that needs to be deleted", 511 | "required": true, 512 | "type": "string", 513 | "minimum": 1 514 | } 515 | ], 516 | "responses": { 517 | "400": { 518 | "description": "Invalid ID supplied" 519 | }, 520 | "404": { 521 | "description": "Order not found" 522 | } 523 | } 524 | } 525 | }, 526 | "/user": { 527 | "post": { 528 | "tags": ["user"], 529 | "summary": "Create user", 530 | "description": "This can only be done by the logged in user.", 531 | "operationId": "createUser", 532 | "produces": ["application/xml", "application/json"], 533 | "parameters": [ 534 | { 535 | "in": "body", 536 | "name": "body", 537 | "description": "Created user object", 538 | "required": true, 539 | "schema": { 540 | "$ref": "#/definitions/User" 541 | } 542 | } 543 | ], 544 | "responses": { 545 | "default": { 546 | "description": "successful operation" 547 | } 548 | } 549 | } 550 | }, 551 | "/user/{username}": { 552 | "get": { 553 | "tags": ["user"], 554 | "summary": "Get user by user name", 555 | "description": "", 556 | "operationId": "getUserByName", 557 | "produces": ["application/xml", "application/json"], 558 | "parameters": [ 559 | { 560 | "name": "username", 561 | "in": "path", 562 | "description": "The name that needs to be fetched. Use user1 for testing. ", 563 | "required": true, 564 | "type": "string" 565 | } 566 | ], 567 | "responses": { 568 | "200": { 569 | "description": "successful operation", 570 | "schema": { 571 | "$ref": "#/definitions/User" 572 | } 573 | }, 574 | "400": { 575 | "description": "Invalid username supplied" 576 | }, 577 | "404": { 578 | "description": "User not found" 579 | } 580 | } 581 | }, 582 | "put": { 583 | "tags": ["user"], 584 | "summary": "Updated user", 585 | "description": "This can only be done by the logged in user.", 586 | "operationId": "updateUser", 587 | "produces": ["application/xml", "application/json"], 588 | "parameters": [ 589 | { 590 | "name": "username", 591 | "in": "path", 592 | "description": "name that need to be deleted", 593 | "required": true, 594 | "type": "string" 595 | }, 596 | { 597 | "in": "body", 598 | "name": "body", 599 | "description": "Updated user object", 600 | "required": true, 601 | "schema": { 602 | "$ref": "#/definitions/User" 603 | } 604 | } 605 | ], 606 | "responses": { 607 | "400": { 608 | "description": "Invalid user supplied" 609 | }, 610 | "404": { 611 | "description": "User not found" 612 | } 613 | } 614 | }, 615 | "delete": { 616 | "tags": ["user"], 617 | "summary": "Delete user", 618 | "description": "This can only be done by the logged in user.", 619 | "operationId": "deleteUser", 620 | "produces": ["application/xml", "application/json"], 621 | "parameters": [ 622 | { 623 | "name": "username", 624 | "in": "path", 625 | "description": "The name that needs to be deleted", 626 | "required": true, 627 | "type": "string" 628 | } 629 | ], 630 | "responses": { 631 | "400": { 632 | "description": "Invalid username supplied" 633 | }, 634 | "404": { 635 | "description": "User not found" 636 | } 637 | } 638 | } 639 | }, 640 | "/user/createWithArray": { 641 | "post": { 642 | "tags": ["user"], 643 | "summary": "Creates list of users with given input array", 644 | "description": "", 645 | "operationId": "createUsersWithArrayInput", 646 | "produces": ["application/xml", "application/json"], 647 | "parameters": [ 648 | { 649 | "in": "body", 650 | "name": "body", 651 | "description": "List of user object", 652 | "required": true, 653 | "schema": { 654 | "type": "array", 655 | "items": { 656 | "$ref": "#/definitions/User" 657 | } 658 | } 659 | } 660 | ], 661 | "responses": { 662 | "default": { 663 | "description": "successful operation" 664 | } 665 | } 666 | } 667 | }, 668 | "/user/createWithList": { 669 | "post": { 670 | "tags": ["user"], 671 | "summary": "Creates list of users with given input array", 672 | "description": "", 673 | "operationId": "createUsersWithListInput", 674 | "produces": ["application/xml", "application/json"], 675 | "parameters": [ 676 | { 677 | "in": "body", 678 | "name": "body", 679 | "description": "List of user object", 680 | "required": true, 681 | "schema": { 682 | "type": "array", 683 | "items": { 684 | "$ref": "#/definitions/User" 685 | } 686 | } 687 | } 688 | ], 689 | "responses": { 690 | "default": { 691 | "description": "successful operation" 692 | } 693 | } 694 | } 695 | }, 696 | "/user/login": { 697 | "get": { 698 | "tags": ["user"], 699 | "summary": "Logs user into the system", 700 | "description": "", 701 | "operationId": "loginUser", 702 | "produces": ["application/xml", "application/json"], 703 | "parameters": [ 704 | { 705 | "name": "username", 706 | "in": "query", 707 | "description": "The user name for login", 708 | "required": true, 709 | "type": "string" 710 | }, 711 | { 712 | "name": "password", 713 | "in": "query", 714 | "description": "The password for login in clear text", 715 | "required": true, 716 | "type": "string" 717 | } 718 | ], 719 | "responses": { 720 | "200": { 721 | "description": "successful operation", 722 | "schema": { 723 | "type": "string" 724 | }, 725 | "examples": { 726 | "application/json": "OK", 727 | "application/xml": " OK ", 728 | "text/plain": "OK" 729 | }, 730 | "headers": { 731 | "X-Rate-Limit": { 732 | "type": "integer", 733 | "format": "int32", 734 | "description": "calls per hour allowed by the user" 735 | }, 736 | "X-Expires-After": { 737 | "type": "string", 738 | "format": "date-time", 739 | "description": "date in UTC when toekn expires" 740 | } 741 | } 742 | }, 743 | "400": { 744 | "description": "Invalid username/password supplied" 745 | } 746 | } 747 | } 748 | }, 749 | "/user/logout": { 750 | "get": { 751 | "tags": ["user"], 752 | "summary": "Logs out current logged in user session", 753 | "description": "", 754 | "operationId": "logoutUser", 755 | "produces": ["application/xml", "application/json"], 756 | "parameters": [], 757 | "responses": { 758 | "default": { 759 | "description": "successful operation" 760 | } 761 | } 762 | } 763 | } 764 | }, 765 | "definitions": { 766 | "ApiResponse": { 767 | "type": "object", 768 | "properties": { 769 | "code": { 770 | "type": "integer", 771 | "format": "int32" 772 | }, 773 | "type": { 774 | "type": "string" 775 | }, 776 | "message": { 777 | "type": "string" 778 | } 779 | } 780 | }, 781 | "Cat": { 782 | "description": "A representation of a cat", 783 | "allOf": [ 784 | { 785 | "$ref": "#/definitions/Pet" 786 | }, 787 | { 788 | "type": "object", 789 | "properties": { 790 | "huntingSkill": { 791 | "type": "string", 792 | "description": "The measured skill for hunting", 793 | "default": "lazy", 794 | "enum": ["clueless", "lazy", "adventurous", "aggressive"] 795 | } 796 | }, 797 | "required": ["huntingSkill"] 798 | } 799 | ] 800 | }, 801 | "Category": { 802 | "type": "object", 803 | "properties": { 804 | "id": { 805 | "description": "Category ID", 806 | "allOf": [ 807 | { 808 | "$ref": "#/definitions/Id" 809 | } 810 | ] 811 | }, 812 | "name": { 813 | "description": "Category name", 814 | "type": "string", 815 | "minLength": 1 816 | }, 817 | "sub": { 818 | "description": "Test Sub Category", 819 | "type": "object", 820 | "properties": { 821 | "prop1": { 822 | "type": "string", 823 | "description": "Dumb Property" 824 | } 825 | } 826 | } 827 | }, 828 | "xml": { 829 | "name": "Category" 830 | } 831 | }, 832 | "Dog": { 833 | "description": "A representation of a dog", 834 | "allOf": [ 835 | { 836 | "$ref": "#/definitions/Pet" 837 | }, 838 | { 839 | "type": "object", 840 | "properties": { 841 | "packSize": { 842 | "type": "integer", 843 | "format": "int32", 844 | "description": "The size of the pack the dog is from", 845 | "default": 1, 846 | "minimum": 1 847 | } 848 | }, 849 | "required": ["packSize"] 850 | } 851 | ] 852 | }, 853 | "HoneyBee": { 854 | "description": "A representation of a honey bee", 855 | "allOf": [ 856 | { 857 | "$ref": "#/definitions/Pet" 858 | }, 859 | { 860 | "type": "object", 861 | "properties": { 862 | "honeyPerDay": { 863 | "type": "number", 864 | "description": "Average amount of honey produced per day in ounces", 865 | "example": 3.14 866 | } 867 | }, 868 | "required": ["honeyPerDay"] 869 | } 870 | ] 871 | }, 872 | "Id": { 873 | "type": "integer", 874 | "format": "int64" 875 | }, 876 | "Order": { 877 | "type": "object", 878 | "properties": { 879 | "id": { 880 | "description": "Order ID", 881 | "allOf": [ 882 | { 883 | "$ref": "#/definitions/Id" 884 | } 885 | ] 886 | }, 887 | "petId": { 888 | "description": "Pet ID", 889 | "allOf": [ 890 | { 891 | "$ref": "#/definitions/Id" 892 | } 893 | ] 894 | }, 895 | "quantity": { 896 | "type": "integer", 897 | "format": "int32", 898 | "minimum": 1, 899 | "default": 1 900 | }, 901 | "shipDate": { 902 | "description": "Estimated ship date", 903 | "type": "string", 904 | "format": "date-time" 905 | }, 906 | "status": { 907 | "type": "string", 908 | "description": "Order Status", 909 | "enum": ["placed", "approved", "delivered"] 910 | }, 911 | "complete": { 912 | "description": "Indicates whenever order was completed or not", 913 | "type": "boolean", 914 | "default": false 915 | } 916 | }, 917 | "xml": { 918 | "name": "Order" 919 | } 920 | }, 921 | "Pet": { 922 | "type": "object", 923 | "required": ["name", "photoUrls"], 924 | "discriminator": "petType", 925 | "properties": { 926 | "id": { 927 | "description": "Pet ID", 928 | "allOf": [ 929 | { 930 | "$ref": "#/definitions/Id" 931 | } 932 | ] 933 | }, 934 | "category": { 935 | "description": "Categories this pet belongs to", 936 | "allOf": [ 937 | { 938 | "$ref": "#/definitions/Category" 939 | } 940 | ] 941 | }, 942 | "name": { 943 | "description": "The name given to a pet", 944 | "type": "string", 945 | "example": "Guru" 946 | }, 947 | "photoUrls": { 948 | "description": "The list of URL to a cute photos featuring pet", 949 | "type": "array", 950 | "xml": { 951 | "name": "photoUrl", 952 | "wrapped": true 953 | }, 954 | "items": { 955 | "type": "string", 956 | "format": "url" 957 | } 958 | }, 959 | "tags": { 960 | "description": "Tags attached to the pet", 961 | "type": "array", 962 | "xml": { 963 | "name": "tag", 964 | "wrapped": true 965 | }, 966 | "items": { 967 | "$ref": "#/definitions/Tag" 968 | } 969 | }, 970 | "status": { 971 | "type": "string", 972 | "description": "Pet status in the store", 973 | "enum": ["available", "pending", "sold"] 974 | }, 975 | "petType": { 976 | "description": "Type of a pet", 977 | "type": "string" 978 | } 979 | }, 980 | "xml": { 981 | "name": "Pet" 982 | } 983 | }, 984 | "Tag": { 985 | "type": "object", 986 | "properties": { 987 | "id": { 988 | "description": "Tag ID", 989 | "allOf": [ 990 | { 991 | "$ref": "#/definitions/Id" 992 | } 993 | ] 994 | }, 995 | "name": { 996 | "description": "Tag name", 997 | "type": "string", 998 | "minLength": 1 999 | } 1000 | }, 1001 | "xml": { 1002 | "name": "Tag" 1003 | } 1004 | }, 1005 | "User": { 1006 | "type": "object", 1007 | "properties": { 1008 | "id": { 1009 | "description": "User ID", 1010 | "$ref": "#/definitions/Id" 1011 | }, 1012 | "username": { 1013 | "description": "User supplied username", 1014 | "type": "string", 1015 | "minLength": 4, 1016 | "example": "John78" 1017 | }, 1018 | "firstName": { 1019 | "description": "User first name", 1020 | "type": "string", 1021 | "minLength": 1, 1022 | "example": "John" 1023 | }, 1024 | "lastName": { 1025 | "description": "User last name", 1026 | "type": "string", 1027 | "minLength": 1, 1028 | "example": "Smith" 1029 | }, 1030 | "email": { 1031 | "description": "User email address", 1032 | "type": "string", 1033 | "format": "email", 1034 | "example": "john.smith@example.com" 1035 | }, 1036 | "password": { 1037 | "type": "string", 1038 | "description": "User password, MUST contain a mix of upper and lower case letters, as well as digits", 1039 | "format": "password", 1040 | "minLength": 8, 1041 | "pattern": "(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])", 1042 | "example": "drowssaP123" 1043 | }, 1044 | "phone": { 1045 | "description": "User phone number in international format", 1046 | "type": "string", 1047 | "pattern": "^\\+(?:[0-9]-?){6,14}[0-9]$", 1048 | "example": "+1-202-555-0192", 1049 | "x-nullable": true 1050 | }, 1051 | "userStatus": { 1052 | "description": "User status", 1053 | "type": "integer", 1054 | "format": "int32" 1055 | } 1056 | }, 1057 | "xml": { 1058 | "name": "User" 1059 | } 1060 | } 1061 | } 1062 | } 1063 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const test = require('tape'); 4 | const OpenAPISnippets = require('../index'); 5 | 6 | const { createHarParameterObjects } = require('../openapi-to-har'); 7 | 8 | const InstagramOpenAPI = require('./instagram_swagger.json'); 9 | const BloggerOpenAPI = require('./blogger_swagger.json'); 10 | const GitHubOpenAPI = require('./github_swagger.json'); 11 | const WatsonOpenAPI = require('./watson_alchemy_language_swagger.json'); 12 | const IBMOpenAPI = require('./ibm_watson_alchemy_data_news_api.json'); 13 | const PetStoreOpenAPI = require('./petstore_swagger.json'); 14 | const PetStoreOpenAPI3 = require('./petstore_oas.json'); 15 | const ParameterSchemaReferenceAPI = require('./parameter_schema_reference'); 16 | const ParameterExampleReferenceAPI = require('./parameter_example_swagger.json'); 17 | const FormDataExampleReferenceAPI = require('./form_data_example.json'); 18 | const FormUrlencodedExampleAPI = require('./form_urlencoded_example.json'); 19 | const MultipleRequestContentReferenceAPI = require('./multiple_request_content.json'); 20 | const ParameterVariationsAPI = require('./parameter_variations_swagger.json'); 21 | 22 | test('Getting snippets should not result in error or undefined', function (t) { 23 | t.plan(1); 24 | 25 | const result = OpenAPISnippets.getSnippets(InstagramOpenAPI, ['c_libcurl']); 26 | t.notEqual(result, undefined); 27 | }); 28 | 29 | test('An invalid target should result in error', function (t) { 30 | t.plan(1); 31 | 32 | try { 33 | const result = OpenAPISnippets.getSnippets(BloggerOpenAPI, ['node_asfd']); 34 | console.log(result); 35 | t.end(); 36 | } catch (err) { 37 | t.equal(err.toString(), 'Error: Invalid target: node_asfd'); 38 | } 39 | }); 40 | 41 | test('Getting snippets for endpoint should not result in error or undefined', function (t) { 42 | t.plan(1); 43 | 44 | const result = OpenAPISnippets.getEndpointSnippets( 45 | InstagramOpenAPI, 46 | '/geographies/{geo-id}/media/recent', 47 | 'get', 48 | ['c_libcurl'] 49 | ); 50 | t.notEqual(result, undefined); 51 | }); 52 | 53 | test('Getting snippets for IBM Watson Alchemy Language should work', function (t) { 54 | t.plan(1); 55 | 56 | const result = OpenAPISnippets.getEndpointSnippets( 57 | IBMOpenAPI, 58 | '/data/GetNews', 59 | 'get', 60 | ['node_request'] 61 | ); 62 | t.notEqual(result, undefined); 63 | }); 64 | 65 | test('Getting snippets for endpoint should contain body', function (t) { 66 | t.plan(2); 67 | // checks the 'Pages' schema... 68 | const result = OpenAPISnippets.getEndpointSnippets( 69 | BloggerOpenAPI, 70 | '/blogs/{blogId}/pages', 71 | 'post', 72 | ['node_request'] 73 | ); 74 | t.true(/body/.test(result.snippets[0].content)); 75 | t.true(/subPage/.test(result.snippets[0].content)); 76 | }); 77 | 78 | test('Getting snippets from OpenAPI 3.0.x should work', function (t) { 79 | t.plan(1); 80 | // checks the 'Pages' schema... 81 | const result = OpenAPISnippets.getEndpointSnippets( 82 | PetStoreOpenAPI3, 83 | '/pets/{id}', 84 | 'get', 85 | ['node_request'] 86 | ); 87 | t.notEqual(result, undefined); 88 | }); 89 | 90 | test('Testing server overrides', function (t) { 91 | t.plan(12); 92 | const result = OpenAPISnippets.getSnippets(PetStoreOpenAPI3, ['c_libcurl']); 93 | t.equal(result[0].url, 'https://method-override.example.com/pets'); 94 | t.match(result[0].snippets[0].content, /.*method-override.example.com.*/); 95 | t.doesNotMatch(result[0].snippets[0].content, /.*petstore.swagger.io.*/); 96 | t.equal(result[1].url, 'http://petstore.swagger.io/api/pets/{id}'); 97 | t.match(result[1].snippets[0].content, /.*petstore.swagger.io.*/); 98 | t.doesNotMatch(result[1].snippets[0].content, /.*example.com.*/); 99 | t.equal(result[2].url, 'https://path-override.example.com/pets'); 100 | t.match(result[2].snippets[0].content, /.*path-override.example.com.*/); 101 | t.doesNotMatch(result[2].snippets[0].content, /.*petstore.swagger.io.*/); 102 | t.equal(result[3].url, 'http://petstore.swagger.io/api/pets/{id}'); 103 | t.match(result[3].snippets[0].content, /.*petstore.swagger.io.*/); 104 | t.doesNotMatch(result[3].snippets[0].content, /.*example.com.*/); 105 | }); 106 | 107 | test('Testing optionally provided parameter values', function (t) { 108 | t.plan(2); 109 | // checks the 'Pages' schema... 110 | const result = OpenAPISnippets.getEndpointSnippets( 111 | InstagramOpenAPI, 112 | '/locations/search', 113 | 'get', 114 | ['node_request'], 115 | { 116 | distance: 5000, 117 | 'not-a-query-param': 'foo', 118 | } 119 | ); 120 | t.true(/5000/.test(result.snippets[0].content)); 121 | t.false(/not-a-query-param/.test(result.snippets[0].content)); 122 | }); 123 | 124 | test('Testing the case when default is present but a value is provided, use the provided value', function (t) { 125 | t.plan(2); 126 | // checks the 'Pages' schema... 127 | const result = OpenAPISnippets.getEndpointSnippets( 128 | GitHubOpenAPI, 129 | '/issues', 130 | 'get', 131 | ['node_request'], 132 | { 133 | filter: 'assigned', 134 | } 135 | ); 136 | t.true(/assigned/.test(result.snippets[0].content)); 137 | t.false(/all/.test(result.snippets[0].content)); // The default value of `filter` is `all` 138 | }); 139 | 140 | test('Testing the case when default is present but no value is provided, use the default', function (t) { 141 | t.plan(2); 142 | // checks the 'Pages' schema... 143 | const result = OpenAPISnippets.getEndpointSnippets( 144 | GitHubOpenAPI, 145 | '/issues', 146 | 'get', 147 | ['node_request'] 148 | ); 149 | t.false(/assigned/.test(result.snippets[0].content)); 150 | t.true(/all/.test(result.snippets[0].content)); // The default value of `filter` is `all` 151 | }); 152 | 153 | test('Referenced query parameters should be resolved', function (t) { 154 | const result = OpenAPISnippets.getEndpointSnippets( 155 | WatsonOpenAPI, 156 | '/html/HTMLExtractDates', 157 | 'get', 158 | ['node_request'] 159 | ); 160 | const snippet = result.snippets[0].content; 161 | t.true(/apikey/.test(snippet)); 162 | t.true(/showSourceText/.test(snippet)); 163 | t.end(); 164 | }); 165 | 166 | test('Resolve samples from nested examples', function (t) { 167 | const result = OpenAPISnippets.getEndpointSnippets( 168 | PetStoreOpenAPI, 169 | '/user', 170 | 'post', 171 | ['node_request'] 172 | ); 173 | const snippet = result.snippets[0].content; 174 | t.true(/username.*John78\'/.test(snippet)); 175 | t.true(/email.*john.smith@example.com\'/.test(snippet)); 176 | t.true(/phone.*\+1\-202\-555\-0192/.test(snippet)); 177 | t.true(/password.*drowssaP123/.test(snippet)); 178 | t.end(); 179 | }); 180 | 181 | test('Parameters that are Schema References Are Dereferenced', function (t) { 182 | const result = OpenAPISnippets.getEndpointSnippets( 183 | ParameterSchemaReferenceAPI, 184 | '/pets', 185 | 'post', 186 | ['node_request'] 187 | ); 188 | const snippet = result.snippets[0].content; 189 | t.true(/pet: 'SOME_OBJECT_VALUE'/.test(snippet)); 190 | t.end(); 191 | }); 192 | 193 | test('Testing the case when an example is provided, use the provided example value', function (t) { 194 | t.plan(2); 195 | const result = OpenAPISnippets.getEndpointSnippets( 196 | ParameterExampleReferenceAPI, 197 | '/pets', 198 | 'get', 199 | ['node_request'] 200 | ); 201 | const snippet = result.snippets[0].content; 202 | t.true(/ {tags: 'dog,cat', limit: '10'}/.test(snippet)); 203 | t.false(/SOME_INTEGER_VALUE/.test(snippet)); 204 | t.end(); 205 | }); 206 | 207 | test('Generate snippet with multipart/form-data', function (t) { 208 | const result = OpenAPISnippets.getEndpointSnippets( 209 | FormDataExampleReferenceAPI, 210 | '/pets', 211 | 'patch', 212 | ['node_request'] 213 | ); 214 | const snippet = result.snippets[0].content; 215 | t.true(/boundary=---011000010111000001101001/.test(snippet)); 216 | t.true( 217 | /formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string'}/.test(snippet) 218 | ); 219 | t.end(); 220 | }); 221 | 222 | test('Generate snippet with multipart/form-data with array', function (t) { 223 | const result = OpenAPISnippets.getEndpointSnippets( 224 | FormDataExampleReferenceAPI, 225 | '/pets/{id}/updatetags', 226 | 'patch', 227 | ['node_request'] 228 | ); 229 | const snippet = result.snippets[0].content; 230 | t.true(/boundary=---011000010111000001101001/.test(snippet)); 231 | t.true(/formData: {'pet\[tags\]': '\["string"\]'}/.test(snippet)); 232 | t.end(); 233 | }); 234 | 235 | test('Generate snippet with multipart/form-data with object', function (t) { 236 | const result = OpenAPISnippets.getEndpointSnippets( 237 | FormDataExampleReferenceAPI, 238 | '/pets/{id}/feedingschedule', 239 | 'patch', 240 | ['node_request'] 241 | ); 242 | const snippet = result.snippets[0].content; 243 | t.true(/boundary=---011000010111000001101001/.test(snippet)); 244 | t.true( 245 | /formData: {'pet\[feedingSchedule\]': '{"time":"string","food":"string"}'}/.test( 246 | snippet 247 | ) 248 | ); 249 | t.end(); 250 | }); 251 | 252 | test('Generate snippets with multiple content types', function (t) { 253 | const result = OpenAPISnippets.getEndpointSnippets( 254 | MultipleRequestContentReferenceAPI, 255 | '/pets', 256 | 'patch', 257 | ['node_request'] 258 | ); 259 | t.equal(result.snippets.length, 2); 260 | for (const snippet of result.snippets) { 261 | if (snippet.mimeType === 'application/json') { 262 | t.true( 263 | /headers: {'content-type': 'application\/json'}/.test(snippet.content) 264 | ); 265 | t.true(/body: {name: 'string', tag: 'string'}/.test(snippet.content)); 266 | } else if (snippet.mimeType === 'multipart/form-data') { 267 | t.true( 268 | /headers: {'content-type': 'multipart\/form-data; boundary=---011000010111000001101001'}/.test( 269 | snippet.content 270 | ) 271 | ); 272 | t.true( 273 | /formData: {'pet\[name\]': 'string', 'pet\[tag\]': 'string', 'pet\[picture\]': 'string'}/.test( 274 | snippet.content 275 | ) 276 | ); 277 | } 278 | } 279 | t.end(); 280 | }); 281 | 282 | test('Query Params Defined for all methods should be resolved', function (t) { 283 | const result = OpenAPISnippets.getEndpointSnippets( 284 | ParameterExampleReferenceAPI, 285 | '/animals', 286 | 'get', 287 | ['node_request'] 288 | ); 289 | const snippet = result.snippets[0].content; 290 | t.true(/ {tags: 'dog,cat', limit: '10'}/.test(snippet)); 291 | t.false(/SOME_INTEGER_VALUE/.test(snippet)); 292 | t.end(); 293 | }); 294 | 295 | test('Query Params Defined for all methods are overriden by method definitions', function (t) { 296 | const result = OpenAPISnippets.getEndpointSnippets( 297 | ParameterExampleReferenceAPI, 298 | '/species', 299 | 'get', 300 | ['node_request'] 301 | ); 302 | const snippet = result.snippets[0].content; 303 | t.true(/ qs: {id: '1,2'}/.test(snippet)); 304 | t.end(); 305 | }); 306 | 307 | test('Snippet for Get with no parameters should work', function (t) { 308 | const result = OpenAPISnippets.getEndpointSnippets( 309 | InstagramOpenAPI, 310 | '/media/popular', 311 | 'get', 312 | ['node_request'] 313 | ); 314 | const snippet = result.snippets[0].content; 315 | t.false(/qs/.test(snippet)); 316 | t.end(); 317 | }); 318 | 319 | test('Testing the application/x-www-form-urlencoded example case', function (t) { 320 | t.plan(2); 321 | const result = OpenAPISnippets.getEndpointSnippets( 322 | FormUrlencodedExampleAPI, 323 | '/auth/token', 324 | 'post', 325 | ['shell_curl'] 326 | ); 327 | const snippet = result.snippets[0].content; 328 | t.match(snippet, /.*--data 'id=id\+example\+value'.*/); 329 | t.match(snippet, /.*--data 'secret=secret\+example\+value'.*/); 330 | t.end(); 331 | }); 332 | 333 | // Tests of createHarParameterObject 334 | 335 | // First a set of path parameter tests from here: https://swagger.io/docs/specification/serialization/#path 336 | 337 | test('Path: test that style and explode default correctly (to "simple" and "false") when neither is specified for path', function (t) { 338 | const parameter = { 339 | name: 'id', 340 | in: 'path', 341 | }; 342 | 343 | const expected = [{ name: 'id', value: '1,2,3' }]; 344 | const actual = createHarParameterObjects(parameter, [1, 2, 3]); 345 | t.deepEqual(actual, expected); 346 | t.end(); 347 | }); 348 | 349 | // Simple style tests: 350 | 351 | test('Path: /users/{id*} with id=5', function (t) { 352 | const parameter = { 353 | name: 'id', 354 | in: 'path', 355 | style: 'simple', 356 | explode: true, 357 | }; 358 | 359 | const expected = [{ name: 'id', value: '5' }]; 360 | const actual = createHarParameterObjects(parameter, 5); 361 | t.deepEqual(actual, expected); 362 | t.end(); 363 | }); 364 | 365 | test('Path: /users/{id*} with id=[3,4,5]', function (t) { 366 | const parameter = { 367 | name: 'id', 368 | in: 'path', 369 | style: 'simple', 370 | explode: true, 371 | }; 372 | 373 | const expected = [{ name: 'id', value: '3,4,5' }]; 374 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 375 | t.deepEqual(actual, expected); 376 | t.end(); 377 | }); 378 | 379 | test('Path: /users/{id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 380 | const parameter = { 381 | name: 'id', 382 | in: 'path', 383 | style: 'simple', 384 | explode: true, 385 | }; 386 | 387 | const expected = [{ name: 'id', value: 'role=admin,firstName=Alex,age=34' }]; 388 | const actual = createHarParameterObjects(parameter, { 389 | role: 'admin', 390 | firstName: 'Alex', 391 | age: 34, 392 | }); 393 | t.deepEqual(actual, expected); 394 | t.end(); 395 | }); 396 | 397 | test('Path: /users/{id} with id=5', function (t) { 398 | const parameter = { 399 | name: 'id', 400 | in: 'path', 401 | style: 'simple', 402 | explode: false, 403 | }; 404 | 405 | const expected = [{ name: 'id', value: '5' }]; 406 | const actual = createHarParameterObjects(parameter, 5); 407 | t.deepEqual(actual, expected); 408 | t.end(); 409 | }); 410 | 411 | test('Path: /users/{id} with id=[3,4,5]', function (t) { 412 | const parameter = { 413 | name: 'id', 414 | in: 'path', 415 | style: 'simple', 416 | explode: false, 417 | }; 418 | 419 | const expected = [{ name: 'id', value: '3,4,5' }]; 420 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 421 | t.deepEqual(actual, expected); 422 | t.end(); 423 | }); 424 | 425 | test('Path: /users/{id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 426 | const parameter = { 427 | name: 'id', 428 | in: 'path', 429 | style: 'simple', 430 | explode: false, 431 | }; 432 | 433 | const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; 434 | const actual = createHarParameterObjects(parameter, { 435 | role: 'admin', 436 | firstName: 'Alex', 437 | age: 34, 438 | }); 439 | t.deepEqual(actual, expected); 440 | t.end(); 441 | }); 442 | 443 | // Label style tests 444 | 445 | test('Path: /users/{.id*} with id=5', function (t) { 446 | const parameter = { 447 | name: 'id', 448 | in: 'path', 449 | style: 'label', 450 | explode: true, 451 | }; 452 | 453 | const expected = [{ name: 'id', value: '.5' }]; 454 | const actual = createHarParameterObjects(parameter, 5); 455 | t.deepEqual(actual, expected); 456 | t.end(); 457 | }); 458 | 459 | test('Path: /users/{.id*} with id=[3,4,5]', function (t) { 460 | const parameter = { 461 | name: 'id', 462 | in: 'path', 463 | style: 'label', 464 | explode: true, 465 | }; 466 | 467 | const expected = [{ name: 'id', value: '.3.4.5' }]; 468 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 469 | t.deepEqual(actual, expected); 470 | t.end(); 471 | }); 472 | 473 | test('Path: /users/{.id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 474 | const parameter = { 475 | name: 'id', 476 | in: 'path', 477 | style: 'label', 478 | explode: true, 479 | }; 480 | 481 | const expected = [{ name: 'id', value: '.role=admin.firstName=Alex.age=34' }]; 482 | const actual = createHarParameterObjects(parameter, { 483 | role: 'admin', 484 | firstName: 'Alex', 485 | age: 34, 486 | }); 487 | t.deepEqual(actual, expected); 488 | t.end(); 489 | }); 490 | 491 | test('Path: /users/{.id} with id=5', function (t) { 492 | const parameter = { 493 | name: 'id', 494 | in: 'path', 495 | style: 'label', 496 | explode: false, 497 | }; 498 | 499 | const expected = [{ name: 'id', value: '.5' }]; 500 | const actual = createHarParameterObjects(parameter, 5); 501 | t.deepEqual(actual, expected); 502 | t.end(); 503 | }); 504 | 505 | test('Path: /users/{.id} with id=[3,4,5]', function (t) { 506 | const parameter = { 507 | name: 'id', 508 | in: 'path', 509 | style: 'label', 510 | explode: false, 511 | }; 512 | 513 | const expected = [{ name: 'id', value: '.3,4,5' }]; 514 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 515 | t.deepEqual(actual, expected); 516 | t.end(); 517 | }); 518 | 519 | test('Path: /users/{.id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 520 | const parameter = { 521 | name: 'id', 522 | in: 'path', 523 | style: 'label', 524 | explode: false, 525 | }; 526 | 527 | const expected = [{ name: 'id', value: '.role,admin,firstName,Alex,age,34' }]; 528 | const actual = createHarParameterObjects(parameter, { 529 | role: 'admin', 530 | firstName: 'Alex', 531 | age: 34, 532 | }); 533 | t.deepEqual(actual, expected); 534 | t.end(); 535 | }); 536 | 537 | // Matrix style tests 538 | 539 | test('Path: /users/{;id*} with id=5', function (t) { 540 | const parameter = { 541 | name: 'id', 542 | in: 'path', 543 | style: 'matrix', 544 | explode: true, 545 | }; 546 | 547 | const expected = [{ name: 'id', value: ';id=5' }]; 548 | const actual = createHarParameterObjects(parameter, 5); 549 | t.deepEqual(actual, expected); 550 | t.end(); 551 | }); 552 | 553 | test('Path: /users/{;id*} with id=[3,4,5]', function (t) { 554 | const parameter = { 555 | name: 'id', 556 | in: 'path', 557 | style: 'matrix', 558 | explode: true, 559 | }; 560 | 561 | const expected = [{ name: 'id', value: ';id=3;id=4;id=5' }]; 562 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 563 | t.deepEqual(actual, expected); 564 | t.end(); 565 | }); 566 | 567 | test('Path: /users/{;id*} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 568 | const parameter = { 569 | name: 'id', 570 | in: 'path', 571 | style: 'matrix', 572 | explode: true, 573 | }; 574 | 575 | const expected = [{ name: 'id', value: ';role=admin;firstName=Alex;age=34' }]; 576 | const actual = createHarParameterObjects(parameter, { 577 | role: 'admin', 578 | firstName: 'Alex', 579 | age: 34, 580 | }); 581 | t.deepEqual(actual, expected); 582 | t.end(); 583 | }); 584 | 585 | test('Path: /users/{;id} with id=5', function (t) { 586 | const parameter = { 587 | name: 'id', 588 | in: 'path', 589 | style: 'matrix', 590 | explode: false, 591 | }; 592 | 593 | const expected = [{ name: 'id', value: ';id=5' }]; 594 | const actual = createHarParameterObjects(parameter, 5); 595 | t.deepEqual(actual, expected); 596 | t.end(); 597 | }); 598 | 599 | test('Path: /users/{;id} with id=[3,4,5]', function (t) { 600 | const parameter = { 601 | name: 'id', 602 | in: 'path', 603 | style: 'matrix', 604 | explode: false, 605 | }; 606 | 607 | const expected = [{ name: 'id', value: ';id=3,4,5' }]; 608 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 609 | t.deepEqual(actual, expected); 610 | t.end(); 611 | }); 612 | 613 | test('Path: /users/{;id} with id= {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 614 | const parameter = { 615 | name: 'id', 616 | in: 'path', 617 | style: 'matrix', 618 | explode: false, 619 | }; 620 | 621 | const expected = [ 622 | { name: 'id', value: ';id=role,admin,firstName,Alex,age,34' }, 623 | ]; 624 | const actual = createHarParameterObjects(parameter, { 625 | role: 'admin', 626 | firstName: 'Alex', 627 | age: 34, 628 | }); 629 | t.deepEqual(actual, expected); 630 | t.end(); 631 | }); 632 | 633 | //// Query Parameters: Test cases from https://swagger.io/docs/specification/serialization/#query 634 | 635 | // Form Tests 636 | 637 | test('Query: /users{?id*} with id= 5', function (t) { 638 | const parameter = { 639 | name: 'id', 640 | in: 'query', 641 | style: 'form', 642 | explode: true, 643 | }; 644 | 645 | const expected = [{ name: 'id', value: '5' }]; 646 | const actual = createHarParameterObjects(parameter, 5); 647 | t.deepEqual(actual, expected); 648 | t.end(); 649 | }); 650 | 651 | test('Query: /users{?id*} with id=[3,4,5]', function (t) { 652 | const parameter = { 653 | name: 'id', 654 | in: 'query', 655 | style: 'form', 656 | explode: true, 657 | }; 658 | 659 | const expected = [ 660 | { name: 'id', value: '3' }, 661 | { name: 'id', value: '4' }, 662 | { name: 'id', value: '5' }, 663 | ]; 664 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 665 | t.deepEqual(actual, expected); 666 | t.end(); 667 | }); 668 | 669 | test('Query: /users{?id*} with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 670 | const parameter = { 671 | name: 'id', 672 | in: 'query', 673 | style: 'form', 674 | explode: true, 675 | }; 676 | 677 | const expected = [ 678 | { name: 'role', value: 'admin' }, 679 | { name: 'firstName', value: 'Alex' }, 680 | { name: 'age', value: '34' }, 681 | ]; 682 | const actual = createHarParameterObjects(parameter, { 683 | role: 'admin', 684 | firstName: 'Alex', 685 | age: 34, 686 | }); 687 | t.deepEqual(actual, expected); 688 | t.end(); 689 | }); 690 | 691 | test('Query: /users{?id} with id= 5', function (t) { 692 | const parameter = { 693 | name: 'id', 694 | in: 'query', 695 | style: 'form', 696 | explode: false, 697 | }; 698 | 699 | const expected = [{ name: 'id', value: '5' }]; 700 | const actual = createHarParameterObjects(parameter, 5); 701 | t.deepEqual(actual, expected); 702 | t.end(); 703 | }); 704 | 705 | test('Query: /users{?id} with id=[3,4,5]', function (t) { 706 | const parameter = { 707 | name: 'id', 708 | in: 'query', 709 | style: 'form', 710 | explode: false, 711 | }; 712 | 713 | const expected = [{ name: 'id', value: '3,4,5' }]; 714 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 715 | t.deepEqual(actual, expected); 716 | t.end(); 717 | }); 718 | 719 | test('Query: /users{?id} with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 720 | const parameter = { 721 | name: 'id', 722 | in: 'query', 723 | style: 'form', 724 | explode: false, 725 | }; 726 | 727 | const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; 728 | const actual = createHarParameterObjects(parameter, { 729 | role: 'admin', 730 | firstName: 'Alex', 731 | age: 34, 732 | }); 733 | t.deepEqual(actual, expected); 734 | t.end(); 735 | }); 736 | 737 | test('Query: test that style and explode default correctly (to "form" and "true") when neither is specified for query', function (t) { 738 | const parameter = { 739 | name: 'id', 740 | in: 'query', 741 | }; 742 | 743 | const expected = [ 744 | { name: 'firstName', value: 'Alex' }, 745 | { name: 'age', value: '34' }, 746 | ]; 747 | const actual = createHarParameterObjects(parameter, { 748 | firstName: 'Alex', 749 | age: 34, 750 | }); 751 | t.deepEqual(actual, expected); 752 | t.end(); 753 | }); 754 | 755 | // Space Delimited Tests 756 | // Note: There are less scenarios for this and no special URI Template 757 | 758 | test('Query: /users{?id*} with id=[3,4,5], spaceDelimited', function (t) { 759 | const parameter = { 760 | name: 'id', 761 | in: 'query', 762 | style: 'spaceDelimited', 763 | explode: true, 764 | }; 765 | 766 | const expected = [ 767 | { name: 'id', value: '3' }, 768 | { name: 'id', value: '4' }, 769 | { name: 'id', value: '5' }, 770 | ]; 771 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 772 | t.deepEqual(actual, expected); 773 | t.end(); 774 | }); 775 | 776 | test('Query: /users{?id} with id=[3,4,5], spaceDelimited', function (t) { 777 | const parameter = { 778 | name: 'id', 779 | in: 'query', 780 | style: 'spaceDelimited', 781 | explode: false, 782 | }; 783 | 784 | const expected = [{ name: 'id', value: '3 4 5' }]; 785 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 786 | t.deepEqual(actual, expected); 787 | t.end(); 788 | }); 789 | 790 | // Pipe Delimited Tests 791 | // Note: There are less scenarios for this and no special URI Template 792 | 793 | test('Query: /users{?id*} with id=[3,4,5], pipeDelimited', function (t) { 794 | const parameter = { 795 | name: 'id', 796 | in: 'query', 797 | style: 'pipeDelimited', 798 | explode: true, 799 | }; 800 | 801 | const expected = [ 802 | { name: 'id', value: '3' }, 803 | { name: 'id', value: '4' }, 804 | { name: 'id', value: '5' }, 805 | ]; 806 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 807 | t.deepEqual(actual, expected); 808 | t.end(); 809 | }); 810 | 811 | test('Query: /users{?id} with id=[3,4,5], pipeDelimited', function (t) { 812 | const parameter = { 813 | name: 'id', 814 | in: 'query', 815 | style: 'pipeDelimited', 816 | explode: false, 817 | }; 818 | 819 | const expected = [{ name: 'id', value: '3|4|5' }]; 820 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 821 | t.deepEqual(actual, expected); 822 | t.end(); 823 | }); 824 | 825 | // DeepObject 826 | // Spec doesn't say what to do if explode false. We just assume deepOject ignores explode 827 | // as no alternative serialization is defined when explode is false. 828 | 829 | test('Query: deepObject with id={"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 830 | const parameter = { 831 | name: 'id', 832 | in: 'query', 833 | style: 'deepObject', 834 | }; 835 | 836 | const expected = [ 837 | { 838 | name: 'id[role]', 839 | value: 'admin', 840 | }, 841 | { 842 | name: 'id[firstName]', 843 | value: 'Alex', 844 | }, 845 | { 846 | name: 'id[age]', 847 | value: '34', 848 | }, 849 | ]; 850 | const actual = createHarParameterObjects(parameter, { 851 | role: 'admin', 852 | firstName: 'Alex', 853 | age: 34, 854 | }); 855 | t.deepEqual(actual, expected); 856 | t.end(); 857 | }); 858 | 859 | //// Header Parameters https://swagger.io/docs/specification/serialization/#header 860 | 861 | test('Header: {id} with X-MyHeader = 5', function (t) { 862 | const parameter = { 863 | name: 'X-MyHeader', 864 | in: 'header', 865 | style: 'simple', 866 | explode: false, 867 | }; 868 | 869 | const expected = [{ name: 'X-MyHeader', value: '5' }]; 870 | const actual = createHarParameterObjects(parameter, 5); 871 | t.deepEqual(actual, expected); 872 | t.end(); 873 | }); 874 | 875 | test('Header: {id} with X-MyHeader = [3,4,5]', function (t) { 876 | const parameter = { 877 | name: 'X-MyHeader', 878 | in: 'header', 879 | style: 'simple', 880 | explode: false, 881 | }; 882 | 883 | const expected = [{ name: 'X-MyHeader', value: '3,4,5' }]; 884 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 885 | t.deepEqual(actual, expected); 886 | t.end(); 887 | }); 888 | 889 | test('Header: {id} with X-MyHeader = {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 890 | const parameter = { 891 | name: 'X-MyHeader', 892 | in: 'header', 893 | style: 'simple', 894 | explode: false, 895 | }; 896 | 897 | const expected = [ 898 | { name: 'X-MyHeader', value: 'role,admin,firstName,Alex,age,34' }, 899 | ]; 900 | const actual = createHarParameterObjects(parameter, { 901 | role: 'admin', 902 | firstName: 'Alex', 903 | age: 34, 904 | }); 905 | t.deepEqual(actual, expected); 906 | t.end(); 907 | }); 908 | 909 | test('Header: {id*} with X-MyHeader = 5', function (t) { 910 | const parameter = { 911 | name: 'X-MyHeader', 912 | in: 'header', 913 | style: 'simple', 914 | explode: true, 915 | }; 916 | 917 | const expected = [{ name: 'X-MyHeader', value: '5' }]; 918 | const actual = createHarParameterObjects(parameter, 5); 919 | t.deepEqual(actual, expected); 920 | t.end(); 921 | }); 922 | 923 | test('Header: {id*} with X-MyHeader = [3,4,5]', function (t) { 924 | const parameter = { 925 | name: 'X-MyHeader', 926 | in: 'header', 927 | style: 'simple', 928 | explode: true, 929 | }; 930 | 931 | const expected = [{ name: 'X-MyHeader', value: '3,4,5' }]; 932 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 933 | t.deepEqual(actual, expected); 934 | t.end(); 935 | }); 936 | 937 | test('Header: {id*} with X-MyHeader = {"role": "admin", "firstName": "Alex", "age": 34}', function (t) { 938 | const parameter = { 939 | name: 'X-MyHeader', 940 | in: 'header', 941 | style: 'simple', 942 | explode: true, 943 | }; 944 | 945 | const expected = [ 946 | { name: 'X-MyHeader', value: 'role=admin,firstName=Alex,age=34' }, 947 | ]; 948 | const actual = createHarParameterObjects(parameter, { 949 | role: 'admin', 950 | firstName: 'Alex', 951 | age: 34, 952 | }); 953 | t.deepEqual(actual, expected); 954 | t.end(); 955 | }); 956 | 957 | test('Header: Test that style and explode default to simple/false when not provided', function (t) { 958 | const parameter = { 959 | name: 'X-MyHeader', 960 | in: 'header', 961 | }; 962 | 963 | const expected = [ 964 | { name: 'X-MyHeader', value: 'role,admin,firstName,Alex,age,34' }, 965 | ]; 966 | const actual = createHarParameterObjects(parameter, { 967 | role: 'admin', 968 | firstName: 'Alex', 969 | age: 34, 970 | }); 971 | t.deepEqual(actual, expected); 972 | t.end(); 973 | }); 974 | 975 | //// Cookie Parameters https://swagger.io/docs/specification/serialization/#cookie 976 | 977 | test("Cookie: Test that it doesn't throw an error if style and explode are missing", function (t) { 978 | const parameter = { 979 | name: 'id', 980 | in: 'cookie', 981 | }; 982 | 983 | let expected = [{ name: 'id', value: '5' }]; 984 | let actual = createHarParameterObjects(parameter, 5); 985 | 986 | t.deepEqual(actual, expected); 987 | 988 | // At the time of writing the spec doesn't actually show any test cases for exploded arrays or objects 989 | // so I assume they are not "legal" 990 | 991 | t.end(); 992 | }); 993 | 994 | test('Cookie: id = 5', function (t) { 995 | const parameter = { 996 | name: 'id', 997 | in: 'cookie', 998 | style: 'form', 999 | explode: true, 1000 | }; 1001 | 1002 | const expected = [{ name: 'id', value: '5' }]; 1003 | const actual = createHarParameterObjects(parameter, 5); 1004 | 1005 | t.deepEqual(actual, expected); 1006 | t.end(); 1007 | }); 1008 | 1009 | test('Cookie: id={id} with id = 5', function (t) { 1010 | const parameter = { 1011 | name: 'id', 1012 | in: 'cookie', 1013 | style: 'form', 1014 | explode: false, 1015 | }; 1016 | 1017 | const expected = [{ name: 'id', value: '5' }]; 1018 | const actual = createHarParameterObjects(parameter, 5); 1019 | 1020 | t.deepEqual(actual, expected); 1021 | t.end(); 1022 | }); 1023 | 1024 | test('Cookie: id={id} with id = [3,4,5]', function (t) { 1025 | const parameter = { 1026 | name: 'id', 1027 | in: 'cookie', 1028 | style: 'form', 1029 | explode: false, 1030 | }; 1031 | 1032 | const expected = [{ name: 'id', value: '3,4,5' }]; 1033 | const actual = createHarParameterObjects(parameter, [3, 4, 5]); 1034 | 1035 | t.deepEqual(actual, expected); 1036 | t.end(); 1037 | }); 1038 | 1039 | test('Cookie: id={id} with id = {role: "admin", firstName: "Alex", age: 34}', function (t) { 1040 | const parameter = { 1041 | name: 'id', 1042 | in: 'cookie', 1043 | style: 'form', 1044 | explode: false, 1045 | }; 1046 | 1047 | const expected = [{ name: 'id', value: 'role,admin,firstName,Alex,age,34' }]; 1048 | const actual = createHarParameterObjects(parameter, { 1049 | role: 'admin', 1050 | firstName: 'Alex', 1051 | age: 34, 1052 | }); 1053 | 1054 | t.deepEqual(actual, expected); 1055 | t.end(); 1056 | }); 1057 | 1058 | //// More Tests with Snippets 1059 | 1060 | const setParameterValues = function ( 1061 | parameter, 1062 | value, 1063 | locationOfParameter, 1064 | locationOfExample, 1065 | style, 1066 | explode 1067 | ) { 1068 | if (typeof style === 'undefined') { 1069 | delete parameter.style; 1070 | } else { 1071 | parameter.style = style; 1072 | } 1073 | if (typeof explode === 'undefined') { 1074 | delete parameter.explode; 1075 | } else { 1076 | parameter.explode = explode; 1077 | } 1078 | delete parameter.default; 1079 | delete parameter.example; 1080 | delete parameter.examples; 1081 | 1082 | parameter.in = locationOfParameter; 1083 | 1084 | if (locationOfExample === 'default') { 1085 | parameter.default = value; 1086 | } else if (locationOfExample === 'example') { 1087 | parameter.example = value; 1088 | } else if (locationOfExample === 'examples') { 1089 | parameter.examples = { 1090 | firstExample: { 1091 | summary: 'This is a summary', 1092 | value, 1093 | }, 1094 | }; 1095 | } 1096 | }; 1097 | 1098 | /** 1099 | * The set of options for testing a parameter scenario 1100 | * @typedef {Object} ParameterOptions 1101 | * @property {string} api - The API to use for the test 1102 | * @property {string} path - The path within the API to use for the test 1103 | * @property {string} method - The method to use on the path 1104 | * @property {string} in - The location of the parameter: `query`, `path`, `header` 1105 | * @property {string} parameterName - The name of the parameter to test with 1106 | * @property {*?} value - The value to assign to either `default`, `example` or the first entry in `examples` 1107 | * @property {string} locationOfExample - The location of the example value: `default`, `example`, `examples`. 1108 | * This parameter determines which of these three locations will have the specified `value`. The other 1109 | * locations will be `undefined`. 1110 | * @property {string?} style - Optional: The serialization style for the parameter. Only `form` and `simple` are fully supported. 1111 | * Per the spec: defaults to `form` for `query` and `cookie` params and defaults to `simple` for `path` and `header` params. 1112 | * @property {boolean?} explode - Optional: Determines if array and object values should be "exploded" into multiple key-value pairs. 1113 | * Per the spec: defaults to `true` only for `form` parameters. Defaults to `false` for all other styles. 1114 | * @property {string} expectedString - A string that is expected to be found in the generated `shell_curl` 1115 | * code snippet for the specified operation/parameter. 1116 | * @property {Object?} values - Optional: A set of key value pairs to use as parameter values. 1117 | */ 1118 | 1119 | /** 1120 | * 1121 | * @param {*} t 1122 | * @param {ParameterOptions} options - The test scenario 1123 | */ 1124 | const runParameterTest = function (t, options) { 1125 | const { 1126 | api, 1127 | path, 1128 | method, 1129 | in: locationOfParameter, 1130 | parameterName, 1131 | value, 1132 | locationOfExample, 1133 | style, 1134 | explode, 1135 | expectedString, 1136 | values, 1137 | } = options; 1138 | 1139 | const apiCopy = JSON.parse(JSON.stringify(api)); 1140 | const parameters = apiCopy.paths[path][method].parameters; 1141 | const parameter = parameters.find((p) => p.name === parameterName); 1142 | setParameterValues( 1143 | parameter, 1144 | value, 1145 | locationOfParameter, 1146 | locationOfExample, 1147 | style, 1148 | explode 1149 | ); 1150 | const result = OpenAPISnippets.getEndpointSnippets( 1151 | apiCopy, 1152 | path, 1153 | method, 1154 | ['shell_curl'], 1155 | values 1156 | ); 1157 | const snippet = result.snippets[0].content; 1158 | 1159 | // note: the shell_curl snippets uriEncode commas in query parameters (but not path parameters). 1160 | // So we'll uriEncode and commas that might be in `expectedString` 1161 | 1162 | const encodedCommaExpectationString = 1163 | locationOfParameter === 'query' 1164 | ? expectedString.replaceAll(',', '%2C') 1165 | : expectedString; 1166 | 1167 | t.true( 1168 | snippet.includes(encodedCommaExpectationString), 1169 | `expected '${encodedCommaExpectationString}' in '${snippet}'` 1170 | ); 1171 | }; 1172 | 1173 | const allPetsScenario = { 1174 | api: ParameterVariationsAPI, 1175 | path: '/pets', 1176 | method: 'get', 1177 | parameterName: 'id', 1178 | }; 1179 | 1180 | const singlePetScenario = { 1181 | api: ParameterVariationsAPI, 1182 | path: '/pets/{id}', 1183 | method: 'get', 1184 | parameterName: 'id', 1185 | }; 1186 | 1187 | test('Query parameter with template {?id} with object value', function (t) { 1188 | const testOptions = Object.assign({}, allPetsScenario, { 1189 | in: 'query', 1190 | parameterName: 'id', 1191 | value: { 1192 | role: 'admin', 1193 | firstName: 'Alex', 1194 | age: 34, 1195 | }, 1196 | explode: false, 1197 | locationOfExample: 'default', 1198 | expectedString: 'id=role%2Cadmin%2CfirstName%2CAlex%2Cage%2C34', 1199 | }); 1200 | runParameterTest(t, testOptions); 1201 | t.end(); 1202 | }); 1203 | 1204 | test('Query parameter with template {?id*} with object value', function (t) { 1205 | const testOptions = Object.assign({}, allPetsScenario, { 1206 | in: 'query', 1207 | parameterName: 'id', 1208 | value: { 1209 | role: 'admin', 1210 | firstName: 'Alex', 1211 | age: 34, 1212 | }, 1213 | explode: true, 1214 | locationOfExample: 'default', 1215 | expectedString: 'role=admin&firstName=Alex&age=34', 1216 | }); 1217 | runParameterTest(t, testOptions); 1218 | t.end(); 1219 | }); 1220 | 1221 | test('Query parameter with template {?id} with array value', function (t) { 1222 | const testOptions = Object.assign({}, allPetsScenario, { 1223 | in: 'query', 1224 | parameterName: 'id', 1225 | value: [3, 4, 5], 1226 | explode: false, 1227 | locationOfExample: 'default', 1228 | expectedString: 'id=3%2C4%2C5', 1229 | }); 1230 | runParameterTest(t, testOptions); 1231 | t.end(); 1232 | }); 1233 | 1234 | test('Query parameter with template {?id*} with array value', function (t) { 1235 | const testOptions = Object.assign({}, allPetsScenario, { 1236 | in: 'query', 1237 | parameterName: 'id', 1238 | value: [3, 4, 5], 1239 | explode: true, 1240 | locationOfExample: 'default', 1241 | expectedString: 'id=3&id=4&id=5', 1242 | }); 1243 | runParameterTest(t, testOptions); 1244 | t.end(); 1245 | }); 1246 | 1247 | test('Query parameter with with spaceDelimited style array value', function (t) { 1248 | const testOptions = Object.assign({}, allPetsScenario, { 1249 | in: 'query', 1250 | parameterName: 'id', 1251 | value: [3, 4, 5], 1252 | style: 'spaceDelimited', 1253 | explode: false, 1254 | locationOfExample: 'default', 1255 | expectedString: 'id=3%204%205', 1256 | }); 1257 | runParameterTest(t, testOptions); 1258 | t.end(); 1259 | }); 1260 | 1261 | test('Query parameter with pipeDelimited array value', function (t) { 1262 | const testOptions = Object.assign({}, allPetsScenario, { 1263 | in: 'query', 1264 | parameterName: 'id', 1265 | value: [3, 4, 5], 1266 | style: 'pipeDelimited', 1267 | explode: false, 1268 | locationOfExample: 'default', 1269 | expectedString: 'id=3%7C4%7C5', 1270 | }); 1271 | runParameterTest(t, testOptions); 1272 | t.end(); 1273 | }); 1274 | 1275 | test('Path parameter with template /pets/{id} with object value', function (t) { 1276 | const testOptions = Object.assign({}, singlePetScenario, { 1277 | in: 'path', 1278 | parameterName: 'id', 1279 | value: { 1280 | role: 'admin', 1281 | firstName: 'Alex', 1282 | age: 34, 1283 | }, 1284 | explode: false, 1285 | locationOfExample: 'example', 1286 | expectedString: '/pets/role,admin,firstName,Alex,age,34', 1287 | }); 1288 | runParameterTest(t, testOptions); 1289 | t.end(); 1290 | }); 1291 | 1292 | test('Path parameter with template /pets/{id*} with object value', function (t) { 1293 | const testOptions = Object.assign({}, singlePetScenario, { 1294 | in: 'path', 1295 | parameterName: 'id', 1296 | value: { 1297 | role: 'admin', 1298 | firstName: 'Alex', 1299 | age: 34, 1300 | }, 1301 | explode: true, 1302 | locationOfExample: 'example', 1303 | expectedString: '/pets/role=admin,firstName=Alex,age=34', 1304 | }); 1305 | runParameterTest(t, testOptions); 1306 | t.end(); 1307 | }); 1308 | 1309 | test('Path parameter with template /pets/{id} with array value', function (t) { 1310 | const testOptions = Object.assign({}, singlePetScenario, { 1311 | in: 'path', 1312 | parameterName: 'id', 1313 | value: [3, 4, 5], 1314 | explode: false, 1315 | locationOfExample: 'example', 1316 | expectedString: 'pets/3,4,5', 1317 | }); 1318 | runParameterTest(t, testOptions); 1319 | t.end(); 1320 | }); 1321 | 1322 | test('Path parameter with template /pets/{id*} with array value', function (t) { 1323 | const testOptions = Object.assign({}, singlePetScenario, { 1324 | in: 'path', 1325 | parameterName: 'id', 1326 | value: [3, 4, 5], 1327 | explode: true, 1328 | locationOfExample: 'example', 1329 | expectedString: 'pets/3,4,5', 1330 | }); 1331 | runParameterTest(t, testOptions); 1332 | t.end(); 1333 | }); 1334 | 1335 | test('Path parameter with template /pets/{.id} with primitive value', function (t) { 1336 | const testOptions = Object.assign({}, singlePetScenario, { 1337 | in: 'path', 1338 | parameterName: 'id', 1339 | value: 5, 1340 | style: 'label', 1341 | explode: false, 1342 | locationOfExample: 'example', 1343 | expectedString: '/pets/.5', 1344 | }); 1345 | runParameterTest(t, testOptions); 1346 | t.end(); 1347 | }); 1348 | 1349 | test('Path parameter with template /pets/{.id*} with primitive value', function (t) { 1350 | const testOptions = Object.assign({}, singlePetScenario, { 1351 | in: 'path', 1352 | parameterName: 'id', 1353 | value: 5, 1354 | explode: true, 1355 | style: 'label', 1356 | locationOfExample: 'example', 1357 | expectedString: '/pets/.5', 1358 | }); 1359 | runParameterTest(t, testOptions); 1360 | t.end(); 1361 | }); 1362 | test('Path parameter with template /pets/{.id} with object value', function (t) { 1363 | const testOptions = Object.assign({}, singlePetScenario, { 1364 | in: 'path', 1365 | parameterName: 'id', 1366 | value: { 1367 | role: 'admin', 1368 | firstName: 'Alex', 1369 | age: 34, 1370 | }, 1371 | style: 'label', 1372 | explode: false, 1373 | locationOfExample: 'example', 1374 | expectedString: '/pets/.role,admin,firstName,Alex,age,34', 1375 | }); 1376 | runParameterTest(t, testOptions); 1377 | t.end(); 1378 | }); 1379 | 1380 | test('Path parameter with template /pets/{.id*} with object value', function (t) { 1381 | const testOptions = Object.assign({}, singlePetScenario, { 1382 | in: 'path', 1383 | parameterName: 'id', 1384 | value: { 1385 | role: 'admin', 1386 | firstName: 'Alex', 1387 | age: 34, 1388 | }, 1389 | explode: true, 1390 | style: 'label', 1391 | locationOfExample: 'example', 1392 | expectedString: '/pets/.role=admin.firstName=Alex.age=34', 1393 | }); 1394 | runParameterTest(t, testOptions); 1395 | t.end(); 1396 | }); 1397 | 1398 | test('Path parameter with template /pets/{.id} with array value', function (t) { 1399 | const testOptions = Object.assign({}, singlePetScenario, { 1400 | in: 'path', 1401 | parameterName: 'id', 1402 | value: [3, 4, 5], 1403 | explode: false, 1404 | style: 'label', 1405 | locationOfExample: 'example', 1406 | expectedString: 'pets/.3,4,5', 1407 | }); 1408 | runParameterTest(t, testOptions); 1409 | t.end(); 1410 | }); 1411 | 1412 | test('Path parameter with template /pets/{.id*} with array value', function (t) { 1413 | const testOptions = Object.assign({}, singlePetScenario, { 1414 | in: 'path', 1415 | parameterName: 'id', 1416 | value: [3, 4, 5], 1417 | explode: true, 1418 | style: 'label', 1419 | locationOfExample: 'example', 1420 | expectedString: 'pets/.3.4.5', 1421 | }); 1422 | runParameterTest(t, testOptions); 1423 | t.end(); 1424 | }); 1425 | 1426 | test('Path parameter with template /pets/{;id} with primitive value', function (t) { 1427 | const testOptions = Object.assign({}, singlePetScenario, { 1428 | in: 'path', 1429 | parameterName: 'id', 1430 | value: 5, 1431 | style: 'matrix', 1432 | explode: false, 1433 | locationOfExample: 'example', 1434 | expectedString: '/pets/;id=5', 1435 | }); 1436 | runParameterTest(t, testOptions); 1437 | t.end(); 1438 | }); 1439 | 1440 | test('Path parameter with template /pets/{;id*} with primitive value', function (t) { 1441 | const testOptions = Object.assign({}, singlePetScenario, { 1442 | in: 'path', 1443 | parameterName: 'id', 1444 | value: 5, 1445 | explode: true, 1446 | style: 'matrix', 1447 | locationOfExample: 'example', 1448 | expectedString: '/pets/;id=5', 1449 | }); 1450 | runParameterTest(t, testOptions); 1451 | t.end(); 1452 | }); 1453 | test('Path parameter with template /pets/{;id} with object value', function (t) { 1454 | const testOptions = Object.assign({}, singlePetScenario, { 1455 | in: 'path', 1456 | parameterName: 'id', 1457 | value: { 1458 | role: 'admin', 1459 | firstName: 'Alex', 1460 | age: 34, 1461 | }, 1462 | style: 'matrix', 1463 | explode: false, 1464 | locationOfExample: 'example', 1465 | expectedString: '/pets/;id=role,admin,firstName,Alex,age,34', 1466 | }); 1467 | runParameterTest(t, testOptions); 1468 | t.end(); 1469 | }); 1470 | 1471 | test('Path parameter with template /pets/{;id*} with object value', function (t) { 1472 | const testOptions = Object.assign({}, singlePetScenario, { 1473 | in: 'path', 1474 | parameterName: 'id', 1475 | value: { 1476 | role: 'admin', 1477 | firstName: 'Alex', 1478 | age: 34, 1479 | }, 1480 | explode: true, 1481 | style: 'matrix', 1482 | locationOfExample: 'example', 1483 | expectedString: '/pets/;role=admin;firstName=Alex;age=34', 1484 | }); 1485 | runParameterTest(t, testOptions); 1486 | t.end(); 1487 | }); 1488 | 1489 | test('Path parameter with template /pets/{;id} with array value', function (t) { 1490 | const testOptions = Object.assign({}, singlePetScenario, { 1491 | in: 'path', 1492 | parameterName: 'id', 1493 | value: [3, 4, 5], 1494 | explode: false, 1495 | style: 'matrix', 1496 | locationOfExample: 'example', 1497 | expectedString: 'pets/;id=3,4,5', 1498 | }); 1499 | runParameterTest(t, testOptions); 1500 | t.end(); 1501 | }); 1502 | 1503 | test('Path parameter with template /pets/{;id*} with array value', function (t) { 1504 | const testOptions = Object.assign({}, singlePetScenario, { 1505 | in: 'path', 1506 | parameterName: 'id', 1507 | value: [3, 4, 5], 1508 | explode: true, 1509 | style: 'matrix', 1510 | locationOfExample: 'example', 1511 | expectedString: 'pets/;id=3;id=4;id=5', 1512 | }); 1513 | runParameterTest(t, testOptions); 1514 | t.end(); 1515 | }); 1516 | 1517 | test('Header parameter with template {id} with object value', function (t) { 1518 | const testOptions = Object.assign({}, singlePetScenario, { 1519 | in: 'header', 1520 | parameterName: 'id', 1521 | value: { 1522 | role: 'admin', 1523 | firstName: 'Alex', 1524 | age: 34, 1525 | }, 1526 | explode: false, 1527 | locationOfExample: 'example', 1528 | expectedString: "--header 'id: role,admin,firstName,Alex,age,34'", 1529 | }); 1530 | runParameterTest(t, testOptions); 1531 | t.end(); 1532 | }); 1533 | 1534 | test('Header parameter with template {id*} with object value', function (t) { 1535 | const testOptions = Object.assign({}, singlePetScenario, { 1536 | in: 'header', 1537 | parameterName: 'id', 1538 | value: { 1539 | role: 'admin', 1540 | firstName: 'Alex', 1541 | age: 34, 1542 | }, 1543 | explode: true, 1544 | locationOfExample: 'example', 1545 | expectedString: "--header 'id: role=admin,firstName=Alex,age=34'", 1546 | }); 1547 | runParameterTest(t, testOptions); 1548 | t.end(); 1549 | }); 1550 | 1551 | test('Header parameter with template {id} with array value', function (t) { 1552 | const testOptions = Object.assign({}, singlePetScenario, { 1553 | in: 'header', 1554 | parameterName: 'id', 1555 | value: [3, 4, 5], 1556 | explode: false, 1557 | locationOfExample: 'example', 1558 | expectedString: "--header 'id: 3,4,5'", 1559 | }); 1560 | runParameterTest(t, testOptions); 1561 | t.end(); 1562 | }); 1563 | 1564 | test('Header parameter with template {id*} with array value', function (t) { 1565 | const testOptions = Object.assign({}, singlePetScenario, { 1566 | in: 'header', 1567 | parameterName: 'id', 1568 | value: [3, 4, 5], 1569 | explode: true, 1570 | locationOfExample: 'example', 1571 | expectedString: "--header 'id: 3,4,5'", 1572 | }); 1573 | runParameterTest(t, testOptions); 1574 | t.end(); 1575 | }); 1576 | 1577 | test('Query parameter with sample given by examples key', function (t) { 1578 | const testOptions = Object.assign({}, allPetsScenario, { 1579 | in: 'query', 1580 | parameterName: 'id', 1581 | value: [3, 4, 5], 1582 | locationOfExample: 'examples', 1583 | expectedString: 'id=3&id=4&id=5', 1584 | }); 1585 | runParameterTest(t, testOptions); 1586 | t.end(); 1587 | }); 1588 | 1589 | test('Path parameter with sample given by examples key', function (t) { 1590 | const testOptions = Object.assign({}, singlePetScenario, { 1591 | in: 'path', 1592 | parameterName: 'id', 1593 | value: [3, 4, 5], 1594 | locationOfExample: 'examples', 1595 | expectedString: '/pets/3,4,5', 1596 | }); 1597 | runParameterTest(t, testOptions); 1598 | t.end(); 1599 | }); 1600 | 1601 | test('Header parameter with sample given by examples key', function (t) { 1602 | const testOptions = Object.assign({}, singlePetScenario, { 1603 | in: 'header', 1604 | parameterName: 'id', 1605 | value: [3, 4, 5], 1606 | locationOfExample: 'examples', 1607 | expectedString: "--header 'id: 3,4,5'", 1608 | }); 1609 | runParameterTest(t, testOptions); 1610 | t.end(); 1611 | }); 1612 | 1613 | test('Header parameter defined in operation overrides header parameter of same name in path', function (t) { 1614 | const result = OpenAPISnippets.getEndpointSnippets( 1615 | ParameterVariationsAPI, 1616 | '/pets/{id}', 1617 | 'get', 1618 | ['shell_curl'] 1619 | ); 1620 | const snippet = result.snippets[0].content; 1621 | t.match(snippet, /--header 'X-MYHEADER: SOME_STRING_VALUE'/); 1622 | t.end(); 1623 | }); 1624 | 1625 | test('Path parameter defined in operation overrides header parameter of same name in path', function (t) { 1626 | const result = OpenAPISnippets.getEndpointSnippets( 1627 | ParameterVariationsAPI, 1628 | '/pets/{id}', 1629 | 'get', 1630 | ['shell_curl'] 1631 | ); 1632 | const snippet = result.snippets[0].content; 1633 | t.match(snippet, /\/pets\/role,admin,firstName,Alex,age,34/); 1634 | t.end(); 1635 | }); 1636 | 1637 | test('Header parameter defined in operation (not in path) object', function (t) { 1638 | const testOptions = Object.assign({}, singlePetScenario, { 1639 | in: 'header', 1640 | parameterName: 'X-MYHEADER', 1641 | value: [3, 4, 5], 1642 | locationOfExample: 'examples', 1643 | expectedString: "--header 'X-MYHEADER: 3,4,5'", 1644 | }); 1645 | runParameterTest(t, testOptions); 1646 | t.end(); 1647 | }); 1648 | 1649 | test('Cookie parameter with explode = true', function (t) { 1650 | const testOptions = Object.assign({}, singlePetScenario, { 1651 | in: 'cookie', 1652 | parameterName: 'id', 1653 | value: 5, 1654 | explode: true, 1655 | locationOfExample: 'example', 1656 | expectedString: '--cookie id=5', 1657 | }); 1658 | runParameterTest(t, testOptions); 1659 | t.end(); 1660 | }); 1661 | 1662 | test('Cookie parameter with template id={id} with primitive value', function (t) { 1663 | const testOptions = Object.assign({}, singlePetScenario, { 1664 | in: 'cookie', 1665 | parameterName: 'id', 1666 | value: 5, 1667 | explode: false, 1668 | locationOfExample: 'examples', 1669 | expectedString: '--cookie id=5', 1670 | }); 1671 | runParameterTest(t, testOptions); 1672 | t.end(); 1673 | }); 1674 | 1675 | test('Cookie parameter with template id={id} with object value', function (t) { 1676 | const testOptions = Object.assign({}, singlePetScenario, { 1677 | in: 'cookie', 1678 | parameterName: 'id', 1679 | value: { 1680 | role: 'admin', 1681 | firstName: 'Alex', 1682 | age: 34, 1683 | }, 1684 | explode: false, 1685 | locationOfExample: 'default', 1686 | expectedString: '--cookie id=role%2Cadmin%2CfirstName%2CAlex%2Cage%2C34', 1687 | }); 1688 | runParameterTest(t, testOptions); 1689 | t.end(); 1690 | }); 1691 | 1692 | test('Cookie parameter with template id={id} with array value', function (t) { 1693 | const testOptions = Object.assign({}, singlePetScenario, { 1694 | in: 'cookie', 1695 | parameterName: 'id', 1696 | value: [3, 4, 5], 1697 | explode: false, 1698 | locationOfExample: 'example', 1699 | expectedString: '--cookie id=3%2C4%2C5', 1700 | }); 1701 | runParameterTest(t, testOptions); 1702 | t.end(); 1703 | }); 1704 | 1705 | test('A reference in an examples object is resolved', function (t) { 1706 | const result = OpenAPISnippets.getEndpointSnippets( 1707 | ParameterVariationsAPI, 1708 | '/animals', 1709 | 'get', 1710 | ['shell_curl'] 1711 | ); 1712 | 1713 | const snippet = result.snippets[0].content; 1714 | t.match(snippet, /tags=dog%2Ccat/); 1715 | t.end(); 1716 | }); 1717 | --------------------------------------------------------------------------------