From 33082ed54f40d4aac61977463f26e8ce3fadb3c7 Mon Sep 17 00:00:00 2001 From: Alban Mouton Date: Tue, 23 Oct 2018 13:04:27 +0200 Subject: [PATCH] feat: work on multipart/form-data support --- package-lock.json | 80 +++++++++++++++++++------------ package.json | 1 + src/MultipartForm.vue | 81 +++++++++++++++++++++++++++++++ src/OpenApi.vue | 17 ++++--- src/RequestForm.vue | 26 +++++++--- test/app.js | 3 +- test/multipart.json | 108 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 274 insertions(+), 42 deletions(-) create mode 100644 src/MultipartForm.vue create mode 100644 test/multipart.json diff --git a/package-lock.json b/package-lock.json index 6d25331..7da1599 100644 --- a/package-lock.json +++ b/package-lock.json @@ -232,6 +232,11 @@ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, "autoprefixer": { "version": "6.7.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", @@ -1591,6 +1596,14 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", @@ -2027,6 +2040,11 @@ "rimraf": "^2.2.8" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -2834,6 +2852,16 @@ "for-in": "^1.0.1" } }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "format-util": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz", @@ -2912,14 +2940,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2939,8 +2965,7 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", @@ -3037,7 +3062,7 @@ "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "^2.1.0" } }, "ignore-walk": { @@ -3075,7 +3100,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -3088,7 +3113,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3136,9 +3160,9 @@ "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { @@ -3165,8 +3189,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { @@ -3181,8 +3205,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -3234,8 +3258,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -3256,10 +3280,10 @@ "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -3334,9 +3358,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -3345,7 +3369,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -3353,7 +3377,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -4504,14 +4528,12 @@ "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, "requires": { "mime-db": "~1.33.0" } diff --git a/package.json b/package.json index 6914ca5..08a2846 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { + "form-data": "^2.3.3", "json-formatter-js": "^2.2.0", "json-schema-ref-parser": "^5.0.3", "json-schema-view-js": "^1.0.1", diff --git a/src/MultipartForm.vue b/src/MultipartForm.vue new file mode 100644 index 0000000..bf32044 --- /dev/null +++ b/src/MultipartForm.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/OpenApi.vue b/src/OpenApi.vue index 6c63e58..d6051b1 100644 --- a/src/OpenApi.vue +++ b/src/OpenApi.vue @@ -58,15 +58,15 @@ - +

Request

- +
Execute
- +

Response

@@ -281,7 +281,12 @@ export default { }, request() { this.currentResponse = null - fetch(this.currentRequest, this.selectedEntry, this.api).then(res => { + let formData + if (this.selectedEntry.requestBody && this.selectedEntry.requestBody.selectedType === 'multipart/form-data') { + formData = this.$refs.requestForm.getFormData() + } + console.log('formData', formData) + fetch(this.currentRequest, this.selectedEntry, this.api, formData).then(res => { this.currentResponse = res }, res => { this.currentResponse = res @@ -294,7 +299,7 @@ export default { * HTTP requests utils */ -function fetch(request, entry, api) { +function fetch(request, entry, api, formData) { let params = Object.assign({}, ...(entry.parameters || []) .filter(p => p.in === 'query' && (p.schema.type === 'array' ? request.params[p.name].length : request.params[p.name])) .map(p => ({ @@ -319,7 +324,7 @@ function fetch(request, entry, api) { } if (entry.requestBody) { httpRequest.headers['Content-type'] = entry.requestBody.selectedType - httpRequest.body = request.body + httpRequest.body = formData || request.body } return Vue.http(httpRequest) } diff --git a/src/RequestForm.vue b/src/RequestForm.vue index 8d6be02..e64211a 100644 --- a/src/RequestForm.vue +++ b/src/RequestForm.vue @@ -1,10 +1,8 @@ diff --git a/test/app.js b/test/app.js index e0450a1..bdc3d41 100644 --- a/test/app.js +++ b/test/app.js @@ -4,7 +4,8 @@ import OpenApi from '../src/OpenApi.vue' import 'vue-material/dist/vue-material.css' import VueResource from 'vue-resource' -import jsonApi from './official-examples/api-with-examples.json' +// import jsonApi from './official-examples/api-with-examples.json' +import jsonApi from './multipart.json' Vue.use(VueResource) Vue.use(VueMaterial) diff --git a/test/multipart.json b/test/multipart.json new file mode 100644 index 0000000..f2368f4 --- /dev/null +++ b/test/multipart.json @@ -0,0 +1,108 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Upload de fichiers et autres contenus multipart/form-data", + "version": "0.2.0", + "contact": { + "name": "Koumoul", + "url": "https://koumoul.com", + "email": "support@koumoul.com" + } + }, + "servers": [{ + "url": "http://localhost:5600/api/v1/datasets" + }], + "paths": { + "/": { + "get": { + "summary": "Lister les jeux de données.", + "operationId": "listDatasets", + "tags": ["Jeux de données"], + "parameters": [{ + "in": "header", + "name": "x-apiKey", + "schema": { + "type": "string" + } + }], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + }, + "post": { + "summary": "Charger un jeu de données", + "operationId": "postDataset", + "tags": ["Jeux de données"], + "parameters": [{ + "in": "header", + "name": "x-apiKey", + "schema": { + "type": "string" + } + }], + "requestBody": { + "description": "Fichier à charger et métadonnées", + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "title": "Dataset", + "properties": { + "id": { + "type": "string", + "description": "Identifier of the dataset" + }, + "title": { + "type": "string", + "description": "Short title of the dataset" + }, + "description": { + "type": "string", + "description": "Detailed description of the dataset" + }, + "schema": { + "type": "array", + "description": "JSON schema of the dataset", + "items": { + "type": "object" + } + }, + "file": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Les informations du jeu de données.", + "content": { + "application/json": { + "schema": { + "title": "Dataset", + "type": "object" + } + } + } + } + } + } + } + }, + "externalDocs": { + "description": "Documentation sur Github", + "url": "https://koumoul-dev.github.io/data-fair/" + } +}