diff --git a/package.json b/package.json index 7269a52..7df65fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "axios-curlirize", - "version": "1.3.7", + "version": "1.3.9", "description": "Axios third-party module to print all axios requests as curl commands in the console. This repository is forked from axios-curlirize and supports use with Node JS without having to enable ES6 imports. This repo was inspired by an issue raised on the origional repository . Special thanks to Anthony Gauthier , the author of axios-curlirize", "main": "src/main.js", "type": "module", @@ -43,6 +43,7 @@ "eslint": "^7.29.0", "expect": "^27.0.6", "express": "^4.17.1", - "mocha": "^9.0.1" + "mocha": "^9.0.1", + "qs": "^6.9.4" } } diff --git a/src/lib/CurlHelper.js b/src/lib/CurlHelper.js index 53ce8e0..5619179 100644 --- a/src/lib/CurlHelper.js +++ b/src/lib/CurlHelper.js @@ -57,14 +57,26 @@ export class CurlHelper { getUrl() { if (this.request.baseURL) { - return this.request.baseURL + "/" + this.request.url; + let baseUrl = this.request.baseURL + let url = this.request.url + let finalUrl = baseUrl + "/" + url + return finalUrl + .replace(/\/{2,}/g, '/') + .replace("http:/", "http://") + .replace("https:/", "https://") } return this.request.url; } getQueryString() { - let params = "", - i = 0; + if (this.request.paramsSerializer) { + const params = this.request.paramsSerializer(this.request.params) + if (!params || params.length === 0) return '' + if (params.startsWith('?')) return params + return `?${params}` + } + let params = "" + let i = 0 for(let param in this.request.params) { if({}.hasOwnProperty.call(this.request.params, param)) { @@ -83,7 +95,6 @@ export class CurlHelper { let url = this.getUrl(); if (this.getQueryString() !== "") { - url = url.charAt(url.length - 1) === "/" ? url.substr(0, url.length - 1) : url; url += this.getQueryString(); } @@ -91,7 +102,7 @@ export class CurlHelper { } generateCommand() { - return `curl ${this.getMethod()} ${this.getHeaders()} ${this.getBody()} "${this.getBuiltURL()}"` + return `curl ${this.getMethod()} "${this.getBuiltURL()}" ${this.getHeaders()} ${this.getBody()}` .trim() .replace(/\s{2,}/g, " "); } diff --git a/tests/curlirize.spec.js b/tests/curlirize.spec.js index e6fdc3b..a6a6c40 100644 --- a/tests/curlirize.spec.js +++ b/tests/curlirize.spec.js @@ -2,7 +2,7 @@ import expect from "expect"; import axios from "axios"; import curlirize from "../src/main.js"; import { CurlHelper } from "../src/lib/CurlHelper.js"; - +import qs from 'qs' import app from "./devapp.js"; curlirize(axios); @@ -51,7 +51,7 @@ describe("Testing curlirize", () => { axios.post("http://localhost:7500/", { dummy: "data" }) .then((res) => { expect(res.config.curlCommand).toBeDefined(); - expect(res.config.curlCommand).toBe(`curl -X POST -H "Content-Type:application/x-www-form-urlencoded" --data '{"dummy":"data"}' "http://localhost:7500/"`); + expect(res.config.curlCommand).toBe(`curl -X POST "http://localhost:7500/" -H "Content-Type:application/x-www-form-urlencoded" --data '{"dummy":"data"}'`); done(); }) .catch((err) => { @@ -63,7 +63,7 @@ describe("Testing curlirize", () => { axios.post("http://localhost:7500/") .then((res) => { expect(res.config.curlCommand).toBeDefined(); - expect(res.config.curlCommand).toBe(`curl -X POST -H "Content-Type:application/x-www-form-urlencoded" "http://localhost:7500/"`); + expect(res.config.curlCommand).toBe(`curl -X POST "http://localhost:7500/" -H "Content-Type:application/x-www-form-urlencoded"`); done(); }) .catch((err) => { @@ -75,7 +75,7 @@ describe("Testing curlirize", () => { axios.post("http://localhost:7500/", null, {headers: {Authorization: "Bearer 123", testHeader: "Testing"}}) .then((res) => { expect(res.config.curlCommand).toBeDefined(); - expect(res.config.curlCommand).toBe("curl -X POST -H \"Content-Type:application/x-www-form-urlencoded\" -H \"Authorization:Bearer 123\" -H \"testHeader:Testing\" \"http://localhost:7500/\""); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/" -H "Content-Type:application/x-www-form-urlencoded" -H "Authorization:Bearer 123" -H "testHeader:Testing"'); done(); }) .catch((err) => { @@ -87,7 +87,70 @@ describe("Testing curlirize", () => { axios.post("http://localhost:7500/", null, {params: {test: 1}}) .then((res) => { expect(res.config.curlCommand).toBeDefined(); - expect(res.config.curlCommand).toBe("curl -X POST -H \"Content-Type:application/x-www-form-urlencoded\" \"http://localhost:7500?test=1\""); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/?test=1" -H "Content-Type:application/x-www-form-urlencoded"'); + done(); + }) + .catch((err) => { + console.error(err); + }); + }); + + it("should return the generated command with a queryString specified in the URL with paramsSerializer", (done) => { + const api = axios.create({ + paramsSerializer: (params) => { + return qs.stringify(params) + } + }) + curlirize(api) + api.post("http://localhost:7500/", null, {params: {test: 1, text: 'sim'}}) + .then((res) => { + expect(res.config.curlCommand).toBeDefined(); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/?test=1&text=sim" -H "Content-Type:application/x-www-form-urlencoded"'); + done(); + }) + .catch((err) => { + console.error(err); + }); + }); + + it("do not add ? if params is empty", (done) => { + axios.post("http://localhost:7500/", null) + .then((res) => { + expect(res.config.curlCommand).toBeDefined(); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/" -H "Content-Type:application/x-www-form-urlencoded"'); + done(); + }) + .catch((err) => { + console.log('--', err) + console.error(err); + }); + }); + + it("do not cut end slash", (done) => { + const api = axios.create({ + baseURL: 'http://localhost:7500', + }) + curlirize(api) + api.post("api/", null, {params: {test: 1, text: 'sim'}}) + .then((res) => { + expect(res.config.curlCommand).toBeDefined(); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/api/?test=1&text=sim" -H "Content-Type:application/x-www-form-urlencoded"'); + done(); + }) + .catch((err) => { + console.error(err); + }); + }); + + it("cut middle slash", (done) => { + const api = axios.create({ + baseURL: 'http://localhost:7500/', + }) + curlirize(api) + api.post("/api/", null, {params: {test: 1, text: 'sim'}}) + .then((res) => { + expect(res.config.curlCommand).toBeDefined(); + expect(res.config.curlCommand).toBe('curl -X POST "http://localhost:7500/api/?test=1&text=sim" -H "Content-Type:application/x-www-form-urlencoded"'); done(); }) .catch((err) => { @@ -110,7 +173,7 @@ describe("Testing curl-helper module", () => { method: "post", url: "http://localhost:7500/", data: { dummy: "data" }, - params: { testParam: "test1", testParamTwo: "test2"} + params: { testParam: "test1", testParamTwo: "test2"} }; const curl = new CurlHelper(fakeConfig); @@ -198,4 +261,4 @@ describe("Testing curl-helper module", () => { expect(curl.getQueryString()).toBe("?testParam=test1&testParamTwo=test2"); done(); }); -}); \ No newline at end of file +}); diff --git a/tests/devapp.js b/tests/devapp.js index b4b808b..085454e 100644 --- a/tests/devapp.js +++ b/tests/devapp.js @@ -10,8 +10,12 @@ app.post("/", (req, res) => { res.send({ hello: "world" }); }); +app.post("/api", (req, res) => { + res.send({ hello: "world" }); +}); + app.listen(7500, () => { console.info("Express dev server listening on port 7500"); }); -export default app; \ No newline at end of file +export default app; diff --git a/yarn.lock b/yarn.lock index 75a4daf..0de8e04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -262,6 +262,14 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -730,6 +738,11 @@ fsevents@~2.3.1: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" @@ -740,6 +753,15 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + glob-parent@^5.1.2, glob-parent@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -786,6 +808,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-symbols@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -1153,6 +1187,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -1268,6 +1307,13 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@^6.9.4: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -1404,6 +1450,15 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"