From eedef97be4d8a32e89e9c83ee68defe0c67e8b04 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 14:35:09 -0700 Subject: [PATCH 1/6] fix: better support for auth --- packages/httpsnippet-client-api/.eslintignore | 2 +- .../{HTTPSNIPPET-LICENSE => LICENSES} | 4 + .../__tests__/__fixtures__/output/cookies.js | 7 + .../__tests__/__fixtures__/output/headers.js | 2 +- .../__tests__/__fixtures__/output/petstore.js | 7 + .../request/application-form-encoded.json | 23 --- .../application-form-encoded/definition.json | 41 ++++ .../request/application-form-encoded/har.json | 31 +++ .../request/application-json.json | 14 -- .../request/application-json/definition.json | 78 ++++++++ .../request/application-json/har.json | 22 +++ .../__fixtures__/request/cookies.json | 14 -- .../request/cookies/definition.json | 34 ++++ .../__fixtures__/request/cookies/har.json | 22 +++ .../__fixtures__/request/custom-method.json | 4 - .../__tests__/__fixtures__/request/full.json | 48 ----- .../__fixtures__/request/full/definition.json | 70 +++++++ .../__fixtures__/request/full/har.json | 56 ++++++ .../__fixtures__/request/headers.json | 14 -- .../request/headers/definition.json | 27 +++ .../__fixtures__/request/headers/har.json | 22 +++ .../__tests__/__fixtures__/request/https.json | 4 - .../request/https/definition.json | 18 ++ .../__fixtures__/request/https/har.json | 12 ++ .../request/jsonObj-multiline.json | 12 -- .../request/jsonObj-multiline/definition.json | 33 ++++ .../request/jsonObj-multiline/har.json | 22 +++ .../request/jsonObj-null-value.json | 19 -- .../jsonObj-null-value/definition.json | 33 ++++ .../request/jsonObj-null-value/har.json | 29 +++ .../__fixtures__/request/multipart-data.json | 38 ++-- .../__fixtures__/request/multipart-file.json | 36 ++-- .../request/multipart-form-data.json | 34 ++-- .../request/petstore/definition.json | 181 ++++++++++++++++++ .../__fixtures__/request/petstore/har.json | 31 +++ .../__tests__/__fixtures__/request/query.json | 19 -- .../request/query/definition.json | 52 +++++ .../__fixtures__/request/query/har.json | 27 +++ .../__tests__/__fixtures__/request/short.json | 4 - .../request/short/definition.json | 18 ++ .../__fixtures__/request/short/har.json | 12 ++ .../__fixtures__/request/text-plain.json | 14 -- .../request/text-plain/definition.json | 28 +++ .../__fixtures__/request/text-plain/har.json | 22 +++ .../__tests__/index.test.js | 34 +++- .../httpsnippet-client-api/package-lock.json | 25 +++ packages/httpsnippet-client-api/package.json | 2 + packages/httpsnippet-client-api/src/index.js | 91 ++++++++- 48 files changed, 1149 insertions(+), 243 deletions(-) rename packages/httpsnippet-client-api/{HTTPSNIPPET-LICENSE => LICENSES} (93%) create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/output/cookies.js create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/custom-method.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/full.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/https.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/har.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/query.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/short.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/har.json delete mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/har.json diff --git a/packages/httpsnippet-client-api/.eslintignore b/packages/httpsnippet-client-api/.eslintignore index c8bf46b3..2dfd40e0 100644 --- a/packages/httpsnippet-client-api/.eslintignore +++ b/packages/httpsnippet-client-api/.eslintignore @@ -1,3 +1,3 @@ -__tests__/__fixtures__/ +__tests__/__fixtures__/output/* coverage/ node_modules/ diff --git a/packages/httpsnippet-client-api/HTTPSNIPPET-LICENSE b/packages/httpsnippet-client-api/LICENSES similarity index 93% rename from packages/httpsnippet-client-api/HTTPSNIPPET-LICENSE rename to packages/httpsnippet-client-api/LICENSES index fbab00b1..9074e4a3 100644 --- a/packages/httpsnippet-client-api/HTTPSNIPPET-LICENSE +++ b/packages/httpsnippet-client-api/LICENSES @@ -1,3 +1,7 @@ +HTTP Snippet +https://www.npmjs.com/package/httpsnippet +-------------------- + The MIT License (MIT) Copyright (c) 2015 Mashape (https://www.mashape.com) diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/cookies.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/cookies.js new file mode 100644 index 00000000..9b9d7961 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/cookies.js @@ -0,0 +1,7 @@ +const sdk = require('api')('https://example.com/openapi.json'); + +sdk.post('/har') + .then(res => res.json()) + .then(res => { + console.log(res); + }); diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/headers.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/headers.js index f697ada2..df52a695 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/headers.js +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/headers.js @@ -1,6 +1,6 @@ const sdk = require('api')('https://example.com/openapi.json'); -sdk.get('/har', {accept: 'application/json', 'x-foo': 'Bar'}) +sdk.get('/har', {'x-foo': 'Bar'}) .then(res => res.json()) .then(res => { console.log(res); diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js new file mode 100644 index 00000000..8ba19437 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js @@ -0,0 +1,7 @@ +const sdk = require('api')('https://example.com/openapi.json'); + +sdk.auth('123').get('/v2/pet/findByStatus', {status: 'available', accept: 'application/xml'}) + .then(res => res.json()) + .then(res => { + console.log(res); + }); diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded.json deleted file mode 100644 index 8dae7d79..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "application/x-www-form-urlencoded" - } - ], - "postData": { - "mimeType": "application/x-www-form-urlencoded", - "params": [ - { - "name": "foo", - "value": "bar" - }, - { - "name": "hello", - "value": "world" - } - ] - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/definition.json new file mode 100644 index 00000000..47b8b6d2 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/definition.json @@ -0,0 +1,41 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "application-form-encoded" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "requestBody": { + "required": true, + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "foo": { + "type": "string" + }, + "hello": { + "type": "string" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/har.json new file mode 100644 index 00000000..db4ba361 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-form-encoded/har.json @@ -0,0 +1,31 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + } + ], + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "hello", + "value": "world" + } + ] + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json.json deleted file mode 100644 index 3b62f0d7..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "application/json" - } - ], - "postData": { - "mimeType": "application/json", - "text": "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}" - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/definition.json new file mode 100644 index 00000000..316beed8 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/definition.json @@ -0,0 +1,78 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "application-json" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "number": { + "type": "number" + }, + "string": { + "type": "string" + }, + "arr": { + "type": "array", + "items": { + "type": "number" + } + }, + "nested": { + "type": "object", + "properties": { + "a": { + "type": "string" + } + } + }, + "arr_mix": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "properties": { + "arr_mix_nested": { + "type": "object", + "properties": {} + } + }, + "type": "object" + } + ] + } + }, + "boolean": { + "type": "boolean" + } + } + } + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/har.json new file mode 100644 index 00000000..f86786f9 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/application-json/har.json @@ -0,0 +1,22 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "application/json" + } + ], + "postData": { + "mimeType": "application/json", + "text": "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}" + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies.json deleted file mode 100644 index 248907cf..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "method": "POST", - "url": "http://mockbin.com/har", - "cookies": [ - { - "name": "foo", - "value": "bar" - }, - { - "name": "bar", - "value": "baz" - } - ] -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/definition.json new file mode 100644 index 00000000..f57e580c --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/definition.json @@ -0,0 +1,34 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "cookies" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "parameters": [ + { + "in": "cookie", + "name": "foo", + "schema": { + "type": "string" + } + }, + { + "in": "cookie", + "name": "bar", + "schema": { + "type": "string" + } + } + ] + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/har.json new file mode 100644 index 00000000..fa3b628d --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/cookies/har.json @@ -0,0 +1,22 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "cookies": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "bar", + "value": "baz" + } + ] + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/custom-method.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/custom-method.json deleted file mode 100644 index 346d7145..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/custom-method.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "method": "PROPFIND", - "url": "http://mockbin.com/har" -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full.json deleted file mode 100644 index 640839a1..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "method": "POST", - "url": "http://mockbin.com/har?key=value", - "httpVersion": "HTTP/1.1", - "queryString": [ - { - "name": "foo", - "value": "bar" - }, - { - "name": "foo", - "value": "baz" - }, - { - "name": "baz", - "value": "abc" - } - ], - "headers": [ - { - "name": "accept", - "value": "application/json" - }, - { - "name": "content-type", - "value": "application/x-www-form-urlencoded" - } - ], - "cookies": [ - { - "name": "foo", - "value": "bar" - }, - { - "name": "bar", - "value": "baz" - } - ], - "postData": { - "mimeType": "application/x-www-form-urlencoded", - "params": [ - { - "name": "foo", - "value": "bar" - } - ] - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/definition.json new file mode 100644 index 00000000..7d08b0d3 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/definition.json @@ -0,0 +1,70 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "full" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "parameters": [ + { + "in": "query", + "name": "key", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "foo", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "foo", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "baz", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + }, + "required": [ + "foo" + ] + } + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/har.json new file mode 100644 index 00000000..7579a527 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/full/har.json @@ -0,0 +1,56 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "POST", + "url": "http://mockbin.com/har?key=value", + "httpVersion": "HTTP/1.1", + "queryString": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "foo", + "value": "baz" + }, + { + "name": "baz", + "value": "abc" + } + ], + "headers": [ + { + "name": "accept", + "value": "application/json" + }, + { + "name": "content-type", + "value": "application/x-www-form-urlencoded" + } + ], + "cookies": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "bar", + "value": "baz" + } + ], + "postData": { + "mimeType": "application/x-www-form-urlencoded", + "params": [ + { + "name": "foo", + "value": "bar" + } + ] + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers.json deleted file mode 100644 index 6f41b382..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "method": "GET", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "accept", - "value": "application/json" - }, - { - "name": "x-foo", - "value": "Bar" - } - ] -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/definition.json new file mode 100644 index 00000000..3b026ecb --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/definition.json @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "headers" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "get": { + "parameters": [ + { + "in": "header", + "name": "x-foo", + "schema": { + "type": "string" + } + } + ] + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/har.json new file mode 100644 index 00000000..0a961360 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/headers/har.json @@ -0,0 +1,22 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "GET", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "accept", + "value": "application/json" + }, + { + "name": "x-foo", + "value": "Bar" + } + ] + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https.json deleted file mode 100644 index 339a88e6..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "method": "GET", - "url": "https://mockbin.com/har" -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/definition.json new file mode 100644 index 00000000..900676b5 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/definition.json @@ -0,0 +1,18 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "https" + }, + "servers": [ + { + "url": "https://mockbin.com" + } + ], + "paths": { + "/har": { + "get": { + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/har.json new file mode 100644 index 00000000..e3286789 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/https/har.json @@ -0,0 +1,12 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "GET", + "url": "https://mockbin.com/har" + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline.json deleted file mode 100644 index ed94a351..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "url": "http://mockbin.com/har", - "method": "POST", - "headers": [{ - "name": "content-type", - "value": "application/json" - }], - "postData": { - "text": "{\n \"foo\": \"bar\"\n}", - "mimeType": "application/json" - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/definition.json new file mode 100644 index 00000000..007e2ff3 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/definition.json @@ -0,0 +1,33 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "jsonObj-multiline" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "foo": { + "type": "string" + } + } + } + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/har.json new file mode 100644 index 00000000..9f382dd8 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-multiline/har.json @@ -0,0 +1,22 @@ +{ + "log": { + "entries": [ + { + "request": { + "url": "http://mockbin.com/har", + "method": "POST", + "headers": [ + { + "name": "content-type", + "value": "application/json" + } + ], + "postData": { + "text": "{\n \"foo\": \"bar\"\n}", + "mimeType": "application/json" + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value.json deleted file mode 100644 index c08860ac..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "url": "http://mockbin.com/har", - "method": "POST", - "headers": [{ - "name": "content-type", - "value": "application/json" - }], - "postData": { - "params": [], - "text": "{\"foo\":null}", - "stored": true, - "mimeType": "application/json", - "size": 0, - "jsonObj": { - "foo":null - }, - "paramsObj": false - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/definition.json new file mode 100644 index 00000000..ab285f62 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/definition.json @@ -0,0 +1,33 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "jsonObj-null-value" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "foo": { + "type": "null" + } + } + } + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/har.json new file mode 100644 index 00000000..bc40a780 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/jsonObj-null-value/har.json @@ -0,0 +1,29 @@ +{ + "log": { + "entries": [ + { + "request": { + "url": "http://mockbin.com/har", + "method": "POST", + "headers": [ + { + "name": "content-type", + "value": "application/json" + } + ], + "postData": { + "params": [], + "text": "{\"foo\":null}", + "stored": true, + "mimeType": "application/json", + "size": 0, + "jsonObj": { + "foo":null + }, + "paramsObj": false + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-data.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-data.json index fb9098fd..a1f16d18 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-data.json +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-data.json @@ -1,20 +1,28 @@ { - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "multipart/form-data" - } - ], - "postData": { - "mimeType": "multipart/form-data", - "params": [ + "log": { + "entries": [ { - "name": "foo", - "value": "Hello World", - "fileName": "hello.txt", - "contentType": "text/plain" + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "multipart/form-data" + } + ], + "postData": { + "mimeType": "multipart/form-data", + "params": [ + { + "name": "foo", + "value": "Hello World", + "fileName": "hello.txt", + "contentType": "text/plain" + } + ] + } + } } ] } diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-file.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-file.json index 8623c1d3..6a15d817 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-file.json +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-file.json @@ -1,19 +1,27 @@ { - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "multipart/form-data" - } - ], - "postData": { - "mimeType": "multipart/form-data", - "params": [ + "log": { + "entries": [ { - "name": "foo", - "fileName": "test/fixtures/files/hello.txt", - "contentType": "text/plain" + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "multipart/form-data" + } + ], + "postData": { + "mimeType": "multipart/form-data", + "params": [ + { + "name": "foo", + "fileName": "test/fixtures/files/hello.txt", + "contentType": "text/plain" + } + ] + } + } } ] } diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-form-data.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-form-data.json index 4db5eeea..62ad5328 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-form-data.json +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/multipart-form-data.json @@ -1,18 +1,26 @@ { - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "multipart/form-data" - } - ], - "postData": { - "mimeType": "multipart/form-data", - "params": [ + "log": { + "entries": [ { - "name": "foo", - "value": "bar" + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "multipart/form-data" + } + ], + "postData": { + "mimeType": "multipart/form-data", + "params": [ + { + "name": "foo", + "value": "bar" + } + ] + } + } } ] } diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/definition.json new file mode 100644 index 00000000..52084a79 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/definition.json @@ -0,0 +1,181 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore" + }, + "servers": [ + { + "url": "http://petstore.swagger.io/v2" + } + ], + "paths": { + "/pet/findByStatus": { + "get": { + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "Status values that need to be considered for filter", + "required": true, + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "available", + "pending", + "sold" + ], + "default": "available" + } + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid status value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + } + }, + "components": { + "securitySchemes": { + "petstore_auth": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "http://petstore.swagger.io/oauth/dialog", + "scopes": { + "write:pets": "modify pets in your account", + "read:pets": "read your pets" + } + } + } + }, + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + } + }, + "schemas": { + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Category" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Tag" + } + }, + "Pet": { + "type": "object", + "required": [ + "name", + "photoUrls" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "name": { + "type": "string", + "example": "doggie" + }, + "photoUrls": { + "type": "array", + "xml": { + "name": "photoUrl", + "wrapped": true + }, + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "xml": { + "name": "tag", + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "xml": { + "name": "Pet" + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/har.json new file mode 100644 index 00000000..5a666cfa --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/petstore/har.json @@ -0,0 +1,31 @@ +{ + "log": { + "entries": [ + { + "request": { + "allHeaders": { + "accept": "application/xml", + "authorization": "Bearer 123" + }, + "cookies": [], + "headers": [ + {"name": "Accept", "value": "application/xml"}, + {"name": "Authorization", "value": "Bearer 123"} + ], + "httpVersion": "HTTP/1.1", + "method": "GET", + "postData": { + "jsonObj": false, + "mimeType": "application/octet-stream", + "paramsObj": false, + "size": 0 + }, + "queryString": [ + {"name": "status", "value": "available"} + ], + "url": "http://petstore.swagger.io/v2/pet/findByStatus" + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query.json deleted file mode 100644 index 5d2e6145..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "method": "GET", - "url": "http://mockbin.com/har?key=value", - "httpVersion": "HTTP/1.1", - "queryString": [ - { - "name": "foo", - "value": "bar" - }, - { - "name": "foo", - "value": "baz" - }, - { - "name": "baz", - "value": "abc" - } - ] -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/definition.json new file mode 100644 index 00000000..5aa40938 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/definition.json @@ -0,0 +1,52 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "query" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "get": { + "parameters": [ + { + "in": "query", + "name": "key", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "foo", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "foo", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "baz", + "schema": { + "type": "string" + }, + "required": true + } + ] + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/har.json new file mode 100644 index 00000000..48aa5b00 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query/har.json @@ -0,0 +1,27 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "GET", + "url": "http://mockbin.com/har?key=value", + "httpVersion": "HTTP/1.1", + "queryString": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "foo", + "value": "baz" + }, + { + "name": "baz", + "value": "abc" + } + ] + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short.json deleted file mode 100644 index a4d8f00a..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "method": "GET", - "url": "http://mockbin.com/har" -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/definition.json new file mode 100644 index 00000000..76c4e033 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/definition.json @@ -0,0 +1,18 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "short" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "get": { + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/har.json new file mode 100644 index 00000000..e9f57c15 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/short/har.json @@ -0,0 +1,12 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "GET", + "url": "http://mockbin.com/har" + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain.json deleted file mode 100644 index 6f6f3072..00000000 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "method": "POST", - "url": "http://mockbin.com/har", - "headers": [ - { - "name": "content-type", - "value": "text/plain" - } - ], - "postData": { - "mimeType": "text/plain", - "text": "Hello World" - } -} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/definition.json new file mode 100644 index 00000000..270f0cb7 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/definition.json @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "text-plain" + }, + "servers": [ + { + "url": "http://mockbin.com" + } + ], + "paths": { + "/har": { + "post": { + "requestBody": { + "required": true, + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/har.json new file mode 100644 index 00000000..efd13328 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/text-plain/har.json @@ -0,0 +1,22 @@ +{ + "log": { + "entries": [ + { + "request": { + "method": "POST", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "content-type", + "value": "text/plain" + } + ], + "postData": { + "mimeType": "text/plain", + "text": "Hello World" + } + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/index.test.js b/packages/httpsnippet-client-api/__tests__/index.test.js index 1383a299..175c07fa 100644 --- a/packages/httpsnippet-client-api/__tests__/index.test.js +++ b/packages/httpsnippet-client-api/__tests__/index.test.js @@ -1,9 +1,12 @@ +/* eslint-disable import/no-dynamic-require, global-require */ + // Most of this has been copied over from the httpsnippet target unit test file. It'd be ideal if this were in a // helper library we could use instead. const fs = require('fs').promises; const HTTPSnippet = require('httpsnippet'); const path = require('path'); const client = require('../src'); +const readmeApi = require('@readme/oas-examples/3.0/json/readme.json'); test('it should have info', () => { expect(client).toHaveProperty('info'); @@ -19,7 +22,20 @@ test('it should have info', () => { ); }); -describe('snippets', () => { +test('it should error if no apiDefinitionUri was supplied', async () => { + HTTPSnippet.addTargetClient('node', client); + + const har = await fs.readFile(path.join(__dirname, `./__fixtures__/request/petstore.json`), 'utf8'); + const snippet = new HTTPSnippet(JSON.parse(har)); + + expect(() => { + snippet.convert('node', 'api'); + }).toThrow(/must have an `apiDefinitionUri` option supplied/); +}); + +test.todo('it should error if no apiDefinition was supplied'); + +describe.only('snippets', () => { beforeAll(() => { HTTPSnippet.addTargetClient('node', client); }); @@ -27,6 +43,7 @@ describe('snippets', () => { it.each([ ['application-form-encoded'], ['application-json'], + ['cookies'], ['full'], ['headers'], ['https'], @@ -38,17 +55,20 @@ describe('snippets', () => { // ['multipart-file'], // ['multipart-form-data'], + ['petstore'], ['query'], ['short'], ['text-plain'], - ])('should generate %s snippet', async testCase => { - const har = await fs.readFile(path.join(__dirname, `./__fixtures__/request/${testCase}.json`), 'utf8'); + ])('should generate `%s` snippet', async testCase => { + const har = require(`./__fixtures__/request/${testCase}/har.json`); + const definition = require(`./__fixtures__/request/${testCase}/definition.json`); const expected = await fs.readFile(path.join(__dirname, `./__fixtures__/output/${testCase}.js`), 'utf8'); - const snippet = new HTTPSnippet(JSON.parse(har)); + const code = new HTTPSnippet(har).convert('node', 'api', { + apiDefinitionUri: 'https://example.com/openapi.json', + apiDefinition: definition, + }); - expect(`${snippet.convert('node', 'api', { apiDefinitionPath: 'https://example.com/openapi.json' })}\n`).toBe( - expected - ); + expect(`${code}\n`).toBe(expected); }); }); diff --git a/packages/httpsnippet-client-api/package-lock.json b/packages/httpsnippet-client-api/package-lock.json index 4c8b953f..7fd0c924 100644 --- a/packages/httpsnippet-client-api/package-lock.json +++ b/packages/httpsnippet-client-api/package-lock.json @@ -952,6 +952,21 @@ "eslint-plugin-unicorn": "^20.0.0" } }, + "@readme/oas-examples": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@readme/oas-examples/-/oas-examples-3.4.0.tgz", + "integrity": "sha512-Wc682b1UMkVZ8YjdEGVglYNy0+UCrBc8Ark9O32pt7/kRWWoWzTrTZCpLqyiyMIC5vAV8LQkzq49MhE0+hnosA==", + "dev": true + }, + "@readme/oas-tooling": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@readme/oas-tooling/-/oas-tooling-3.4.5.tgz", + "integrity": "sha512-180iNHjAbyx9EMB2sE5SzUuSisssXKlcL2HmS07m8YA2pcAizf1W9AWnbg8v47F39CYyri5RdRzFgLb6pNrPjg==", + "requires": { + "jsonpointer": "^4.0.1", + "path-to-regexp": "^6.1.0" + } + }, "@sinonjs/commons": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", @@ -5409,6 +5424,11 @@ "minimist": "^1.2.5" } }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6024,6 +6044,11 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.1.0.tgz", + "integrity": "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==" + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", diff --git a/packages/httpsnippet-client-api/package.json b/packages/httpsnippet-client-api/package.json index 490ece67..3c44db20 100644 --- a/packages/httpsnippet-client-api/package.json +++ b/packages/httpsnippet-client-api/package.json @@ -23,6 +23,7 @@ "node": ">=10" }, "dependencies": { + "@readme/oas-tooling": "^3.4.5", "content-type": "^1.0.4", "httpsnippet": "^1.20.0", "stringify-object": "^3.3.0" @@ -32,6 +33,7 @@ }, "devDependencies": { "@readme/eslint-config": "^3.2.0", + "@readme/oas-examples": "^3.4.0", "eslint": "^7.1.0", "jest": "^26.0.1", "prettier": "^2.0.5" diff --git a/packages/httpsnippet-client-api/src/index.js b/packages/httpsnippet-client-api/src/index.js index 9d9693fb..11794ea7 100644 --- a/packages/httpsnippet-client-api/src/index.js +++ b/packages/httpsnippet-client-api/src/index.js @@ -1,28 +1,108 @@ +/* eslint-disable prettier/prettier */ const stringifyObject = require('stringify-object'); const CodeBuilder = require('httpsnippet/src/helpers/code-builder'); const contentType = require('content-type'); +const OAS = require('@readme/oas-tooling'); + +function buildAuthSnippet(authKey) { + return `.auth('${authKey.replace("'", "\\'")}')`; +} + +function buildAuthMatchers(source, operation) { + const matchers = { + header: [], + query: [], + cookie: [] + }; + + if (operation.getSecurity().length === 0) { + return matchers; + } + + const security = operation.prepareSecurity(); + Object.keys(security).forEach(id => { + security[id].forEach(scheme => { + if (scheme.type === 'http') { + if (scheme.scheme === 'basic') { + matchers.header.authorization = 'Basic'; + } else if (scheme.scheme === 'bearer') { + matchers.header.authorization = 'Bearer'; + } + } else if (scheme.type === 'oauth2') { + matchers.header.authorization = 'Bearer'; + } else if (scheme.type === 'apiKey') { + if (scheme.in === 'query') { + matchers.query.push(scheme.name); + } else if (scheme.in === 'header') { + matchers.header[scheme.name] = '*'; + } else if (scheme.in === 'cookie') { + matchers.cookie.push(scheme.name); + } + } + }) + }); + + return matchers; +} module.exports = function (source, options) { const opts = { indent: ' ', ...options }; + if (!('apiDefinitionUri' in opts)) { + throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.'); + } else if (!('apiDefinition' in opts)) { + throw new Error('This HTTP Snippet client must have an `apiDefinition` option supplied to it.'); + } + + const url = source.url; + const method = source.method.toLowerCase(); + const oas = new OAS(opts.apiDefinition); + const operation = oas.getOperation(url, method); + + // console.log(operation) + + const authData = []; + const authMatchers = buildAuthMatchers(source, operation); + let includeFS = false; const code = new CodeBuilder(opts.indent); - code.push(`const sdk = require('api')('${opts.apiDefinitionPath}');`).blank(); + code.push(`const sdk = require('api')('${opts.apiDefinitionUri}');`).blank(); let metadata = {}; if (Object.keys(source.queryObj).length) { + // @todo query-based auth metadata = Object.assign(metadata, source.queryObj); } if (Object.keys(source.headersObj).length) { const headers = source.headersObj; + Object.keys(headers).forEach(header => { - if (header === 'content-type') { + if (header in authMatchers.header) { + // If this header has been set up as an authentication header, let's remove it and add it into our auth data + // so we can build up an `.auth()` snippet for the SDK. + const headerPrefix = authMatchers.header[header] + if (headerPrefix === '*') { + authData.push(buildAuthSnippet(headers[header])); + } else { + authData.push(buildAuthSnippet(headers[header].replace(`${authMatchers.header[header]} `, ''))); + } + + delete headers[header]; + } else if (header === 'content-type') { + // Content-Type headers are automatically added within the SDK so we can filter them out if they don't have + // parameters attached to them. const parsedContentType = contentType.parse(headers[header]); if (!Object.keys(parsedContentType.parameters).length) { delete headers[header]; } + } else if (header === 'accept') { + // If the accept header here is not the default/first accept header for the operations request body, then we + // should add it, otherwise just let the SDK handle it itself. + if (headers[header] === operation.getContentType()) { + delete headers[header]; + } } }); @@ -78,6 +158,11 @@ module.exports = function (source, options) { } } + let authCode = []; + if (authData.length) { + authCode = authData; + } + const accessors = [`'${source.uriObj.pathname}'`]; if (typeof body !== 'undefined') { accessors.push(stringifyObject(body, { indent: ' ', inlineCharacterLimit: 80 })); @@ -91,7 +176,7 @@ module.exports = function (source, options) { code.unshift('const fs = require("fs");'); } - code.push(`sdk.${source.method.toLowerCase()}(${accessors.join(', ')})`); + code.push(`sdk${authCode.join()}.${method}(${accessors.join(', ')})`); code.push(1, '.then(res => res.json())'); code.push(1, '.then(res => {'); code.push(2, 'console.log(res);'); From 107aefe46f697f51d02d0fd7181af234448aae7f Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 17:31:50 -0700 Subject: [PATCH 2/6] feat: adding support for operation ids to code snippets --- .../__tests__/__fixtures__/output/petstore.js | 2 +- .../__tests__/index.test.js | 18 ++++++++++--- .../httpsnippet-client-api/package-lock.json | 6 ----- packages/httpsnippet-client-api/package.json | 1 - packages/httpsnippet-client-api/src/index.js | 25 +++++++++++-------- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js index 8ba19437..aeae4470 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/petstore.js @@ -1,6 +1,6 @@ const sdk = require('api')('https://example.com/openapi.json'); -sdk.auth('123').get('/v2/pet/findByStatus', {status: 'available', accept: 'application/xml'}) +sdk.auth('123').findPetsByStatus({status: 'available', accept: 'application/xml'}) .then(res => res.json()) .then(res => { console.log(res); diff --git a/packages/httpsnippet-client-api/__tests__/index.test.js b/packages/httpsnippet-client-api/__tests__/index.test.js index 175c07fa..7f12cda2 100644 --- a/packages/httpsnippet-client-api/__tests__/index.test.js +++ b/packages/httpsnippet-client-api/__tests__/index.test.js @@ -6,7 +6,6 @@ const fs = require('fs').promises; const HTTPSnippet = require('httpsnippet'); const path = require('path'); const client = require('../src'); -const readmeApi = require('@readme/oas-examples/3.0/json/readme.json'); test('it should have info', () => { expect(client).toHaveProperty('info'); @@ -25,7 +24,7 @@ test('it should have info', () => { test('it should error if no apiDefinitionUri was supplied', async () => { HTTPSnippet.addTargetClient('node', client); - const har = await fs.readFile(path.join(__dirname, `./__fixtures__/request/petstore.json`), 'utf8'); + const har = await fs.readFile(path.join(__dirname, `./__fixtures__/request/petstore/har.json`), 'utf8'); const snippet = new HTTPSnippet(JSON.parse(har)); expect(() => { @@ -33,9 +32,20 @@ test('it should error if no apiDefinitionUri was supplied', async () => { }).toThrow(/must have an `apiDefinitionUri` option supplied/); }); -test.todo('it should error if no apiDefinition was supplied'); +test('it should error if no apiDefinition was supplied', async () => { + HTTPSnippet.addTargetClient('node', client); + + const har = await fs.readFile(path.join(__dirname, `./__fixtures__/request/petstore/har.json`), 'utf8'); + const snippet = new HTTPSnippet(JSON.parse(har)); + + expect(() => { + snippet.convert('node', 'api', { + apiDefinitionUri: 'https://example.com/openapi.json', + }); + }).toThrow(/must have an `apiDefinition` option supplied/); +}); -describe.only('snippets', () => { +describe('snippets', () => { beforeAll(() => { HTTPSnippet.addTargetClient('node', client); }); diff --git a/packages/httpsnippet-client-api/package-lock.json b/packages/httpsnippet-client-api/package-lock.json index 7fd0c924..cae31720 100644 --- a/packages/httpsnippet-client-api/package-lock.json +++ b/packages/httpsnippet-client-api/package-lock.json @@ -952,12 +952,6 @@ "eslint-plugin-unicorn": "^20.0.0" } }, - "@readme/oas-examples": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@readme/oas-examples/-/oas-examples-3.4.0.tgz", - "integrity": "sha512-Wc682b1UMkVZ8YjdEGVglYNy0+UCrBc8Ark9O32pt7/kRWWoWzTrTZCpLqyiyMIC5vAV8LQkzq49MhE0+hnosA==", - "dev": true - }, "@readme/oas-tooling": { "version": "3.4.5", "resolved": "https://registry.npmjs.org/@readme/oas-tooling/-/oas-tooling-3.4.5.tgz", diff --git a/packages/httpsnippet-client-api/package.json b/packages/httpsnippet-client-api/package.json index 3c44db20..9c472e50 100644 --- a/packages/httpsnippet-client-api/package.json +++ b/packages/httpsnippet-client-api/package.json @@ -33,7 +33,6 @@ }, "devDependencies": { "@readme/eslint-config": "^3.2.0", - "@readme/oas-examples": "^3.4.0", "eslint": "^7.1.0", "jest": "^26.0.1", "prettier": "^2.0.5" diff --git a/packages/httpsnippet-client-api/src/index.js b/packages/httpsnippet-client-api/src/index.js index 11794ea7..38f17d84 100644 --- a/packages/httpsnippet-client-api/src/index.js +++ b/packages/httpsnippet-client-api/src/index.js @@ -1,4 +1,3 @@ -/* eslint-disable prettier/prettier */ const stringifyObject = require('stringify-object'); const CodeBuilder = require('httpsnippet/src/helpers/code-builder'); const contentType = require('content-type'); @@ -12,7 +11,7 @@ function buildAuthMatchers(source, operation) { const matchers = { header: [], query: [], - cookie: [] + cookie: [], }; if (operation.getSecurity().length === 0) { @@ -39,7 +38,7 @@ function buildAuthMatchers(source, operation) { matchers.cookie.push(scheme.name); } } - }) + }); }); return matchers; @@ -59,8 +58,6 @@ module.exports = function (source, options) { const oas = new OAS(opts.apiDefinition); const operation = oas.getOperation(url, method); - // console.log(operation) - const authData = []; const authMatchers = buildAuthMatchers(source, operation); @@ -82,7 +79,7 @@ module.exports = function (source, options) { if (header in authMatchers.header) { // If this header has been set up as an authentication header, let's remove it and add it into our auth data // so we can build up an `.auth()` snippet for the SDK. - const headerPrefix = authMatchers.header[header] + const headerPrefix = authMatchers.header[header]; if (headerPrefix === '*') { authData.push(buildAuthSnippet(headers[header])); } else { @@ -163,20 +160,28 @@ module.exports = function (source, options) { authCode = authData; } - const accessors = [`'${source.uriObj.pathname}'`]; + const args = []; + + let accessor = method; + if ('operationId' in operation && operation.operationId.length > 0) { + accessor = operation.operationId; + } else { + args.push(`'${source.uriObj.pathname}'`); + } + if (typeof body !== 'undefined') { - accessors.push(stringifyObject(body, { indent: ' ', inlineCharacterLimit: 80 })); + args.push(stringifyObject(body, { indent: ' ', inlineCharacterLimit: 80 })); } if (Object.keys(metadata).length > 0) { - accessors.push(stringifyObject(metadata, { indent: ' ', inlineCharacterLimit: 80 })); + args.push(stringifyObject(metadata, { indent: ' ', inlineCharacterLimit: 80 })); } if (includeFS) { code.unshift('const fs = require("fs");'); } - code.push(`sdk${authCode.join()}.${method}(${accessors.join(', ')})`); + code.push(`sdk${authCode.join()}.${accessor}(${args.join(', ')})`); code.push(1, '.then(res => res.json())'); code.push(1, '.then(res => {'); code.push(2, 'console.log(res);'); From 4fd07141d17413cb9674955ea4510d33086d9cd5 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 17:55:19 -0700 Subject: [PATCH 3/6] feat: adding support for query-based auth --- .../__fixtures__/output/query-auth.js | 7 +++ .../request/query-auth/definition.json | 58 +++++++++++++++++++ .../__fixtures__/request/query-auth/har.json | 31 ++++++++++ .../__tests__/index.test.js | 1 + packages/httpsnippet-client-api/src/index.js | 23 +++++--- 5 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/definition.json create mode 100644 packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js new file mode 100644 index 00000000..f0a35a4a --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js @@ -0,0 +1,7 @@ +const sdk = require('api')('https://example.com/openapi.json'); + +sdk.auth('a5a220e544b16e733f59e5fe681366dd').findPetsByStatus({status: 'available', accept: 'application/xml'}) + .then(res => res.json()) + .then(res => { + console.log(res); + }); diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/definition.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/definition.json new file mode 100644 index 00000000..18b56535 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/definition.json @@ -0,0 +1,58 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "query-auth" + }, + "servers": [ + { + "url": "http://petstore.swagger.io/v2" + } + ], + "paths": { + "/pet/findByStatus": { + "get": { + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "required": true, + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "available", + "pending", + "sold" + ], + "default": "available" + } + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + } + }, + "components": { + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "query" + } + } + } +} diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json new file mode 100644 index 00000000..f06804e2 --- /dev/null +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json @@ -0,0 +1,31 @@ +{ + "log": { + "entries": [ + { + "request": { + "allHeaders": { + "accept": "application/xml", + "authorization": "Bearer 123" + }, + "cookies": [], + "headers": [ + {"name": "Accept", "value": "application/xml"} + ], + "httpVersion": "HTTP/1.1", + "method": "GET", + "postData": { + "jsonObj": false, + "mimeType": "application/octet-stream", + "paramsObj": false, + "size": 0 + }, + "queryString": [ + {"name": "status", "value": "available"}, + {"name": "api_key", "value": "a5a220e544b16e733f59e5fe681366dd"} + ], + "url": "http://petstore.swagger.io/v2/pet/findByStatus" + } + } + ] + } +} diff --git a/packages/httpsnippet-client-api/__tests__/index.test.js b/packages/httpsnippet-client-api/__tests__/index.test.js index 7f12cda2..7720111e 100644 --- a/packages/httpsnippet-client-api/__tests__/index.test.js +++ b/packages/httpsnippet-client-api/__tests__/index.test.js @@ -67,6 +67,7 @@ describe('snippets', () => { ['petstore'], ['query'], + ['query-auth'], ['short'], ['text-plain'], ])('should generate `%s` snippet', async testCase => { diff --git a/packages/httpsnippet-client-api/src/index.js b/packages/httpsnippet-client-api/src/index.js index 38f17d84..306a883c 100644 --- a/packages/httpsnippet-client-api/src/index.js +++ b/packages/httpsnippet-client-api/src/index.js @@ -7,7 +7,7 @@ function buildAuthSnippet(authKey) { return `.auth('${authKey.replace("'", "\\'")}')`; } -function buildAuthMatchers(source, operation) { +function getAuthSources(operation) { const matchers = { header: [], query: [], @@ -59,7 +59,7 @@ module.exports = function (source, options) { const operation = oas.getOperation(url, method); const authData = []; - const authMatchers = buildAuthMatchers(source, operation); + const authSources = getAuthSources(operation); let includeFS = false; const code = new CodeBuilder(opts.indent); @@ -68,22 +68,31 @@ module.exports = function (source, options) { let metadata = {}; if (Object.keys(source.queryObj).length) { - // @todo query-based auth - metadata = Object.assign(metadata, source.queryObj); + const queryParams = source.queryObj; + + Object.keys(queryParams).forEach(param => { + if (authSources.query.includes(param)) { + authData.push(buildAuthSnippet(queryParams[param])); + + delete queryParams[param]; + } + }); + + metadata = Object.assign(metadata, queryParams); } if (Object.keys(source.headersObj).length) { const headers = source.headersObj; Object.keys(headers).forEach(header => { - if (header in authMatchers.header) { + if (header in authSources.header) { // If this header has been set up as an authentication header, let's remove it and add it into our auth data // so we can build up an `.auth()` snippet for the SDK. - const headerPrefix = authMatchers.header[header]; + const headerPrefix = authSources.header[header]; if (headerPrefix === '*') { authData.push(buildAuthSnippet(headers[header])); } else { - authData.push(buildAuthSnippet(headers[header].replace(`${authMatchers.header[header]} `, ''))); + authData.push(buildAuthSnippet(headers[header].replace(`${authSources.header[header]} `, ''))); } delete headers[header]; From d42c400a7f7ea6aa758c67e37b1644e3b425996b Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 17:57:26 -0700 Subject: [PATCH 4/6] test: commenting out the cookies test since cookies are unsupported --- packages/httpsnippet-client-api/__tests__/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/httpsnippet-client-api/__tests__/index.test.js b/packages/httpsnippet-client-api/__tests__/index.test.js index 7720111e..5aab54f1 100644 --- a/packages/httpsnippet-client-api/__tests__/index.test.js +++ b/packages/httpsnippet-client-api/__tests__/index.test.js @@ -53,7 +53,7 @@ describe('snippets', () => { it.each([ ['application-form-encoded'], ['application-json'], - ['cookies'], + // ['cookies'], // @todo ['full'], ['headers'], ['https'], From 70ba47363fc10f8de20617b51b22023140c1c9fe Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 17:58:50 -0700 Subject: [PATCH 5/6] test: slimming down the query-auth example a bit --- .../__tests__/__fixtures__/output/query-auth.js | 2 +- .../__tests__/__fixtures__/request/query-auth/har.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js index f0a35a4a..ba2e19bc 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/output/query-auth.js @@ -1,6 +1,6 @@ const sdk = require('api')('https://example.com/openapi.json'); -sdk.auth('a5a220e544b16e733f59e5fe681366dd').findPetsByStatus({status: 'available', accept: 'application/xml'}) +sdk.auth('a5a220e').findPetsByStatus({status: 'available', accept: 'application/xml'}) .then(res => res.json()) .then(res => { console.log(res); diff --git a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json index f06804e2..9a22ecf2 100644 --- a/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json +++ b/packages/httpsnippet-client-api/__tests__/__fixtures__/request/query-auth/har.json @@ -21,7 +21,7 @@ }, "queryString": [ {"name": "status", "value": "available"}, - {"name": "api_key", "value": "a5a220e544b16e733f59e5fe681366dd"} + {"name": "api_key", "value": "a5a220e"} ], "url": "http://petstore.swagger.io/v2/pet/findByStatus" } From da9a2525c62684cb8a9621bed8bc2bd8b94ef21e Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 11 Jun 2020 18:00:35 -0700 Subject: [PATCH 6/6] docs: updating the usage docs --- packages/httpsnippet-client-api/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/httpsnippet-client-api/README.md b/packages/httpsnippet-client-api/README.md index e44a7b5b..20e90509 100644 --- a/packages/httpsnippet-client-api/README.md +++ b/packages/httpsnippet-client-api/README.md @@ -24,7 +24,10 @@ HTTPSnippet.addTargetClient('node', client); const snippet = new HTTPSnippet(harObject); console.log( snippet.convert('node', 'api', { - apiDefinitionPath: 'https://example.com/openapi.json' + apiDefinitionUri: 'https://example.com/openapi.json' + apiDefinition: { + /* an OpenAPI definition object */ + } }) ); ```