├── .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 [](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 |
--------------------------------------------------------------------------------