diff --git a/src/generate-axios-client.test.ts b/src/generate-axios-client.test.ts index 67f9df7..0c893f7 100644 --- a/src/generate-axios-client.test.ts +++ b/src/generate-axios-client.test.ts @@ -68,12 +68,16 @@ const substituteParams = (url, params) => url ); -const removePathParams = (url, params) => - Object.entries(params).reduce( - (accum, [name, value]) => - url.includes(":" + name) ? accum : { ...accum, [name]: value }, - {} - ); +const removePathParams = (url, params, encode) => + Object.entries(params) + .filter(([key, value]) => value !== undefined) + .reduce( + (accum, [name, value]) => + url.includes(":" + name) + ? accum + : { ...accum, [name]: encode ? encodeURIComponent(value) : value }, + {} + ); const parseQueryParamsFromPagingLink = (link) => { const params = new URLSearchParams(link.split("?")[1]); @@ -89,12 +93,12 @@ class Client { this.client = client; } - getPosts(params, config) { + getPosts(data, config) { return this.client.request({ ...config, method: "GET", - params: removePathParams("/posts", params), - url: substituteParams("/posts", params), + params: removePathParams("/posts", data, true), + url: substituteParams("/posts", data), }); } @@ -102,7 +106,7 @@ class Client { return this.client.request({ ...config, method: "PUT", - data: removePathParams("/posts/:id", data), + data: removePathParams("/posts/:id", data, false), url: substituteParams("/posts/:id", data), }); } diff --git a/src/generate-axios-client.ts b/src/generate-axios-client.ts index af49182..63ac518 100644 --- a/src/generate-axios-client.ts +++ b/src/generate-axios-client.ts @@ -64,12 +64,16 @@ const substituteParams = (url, params) => url ); -const removePathParams = (url, params) => - Object.entries(params).reduce( - (accum, [name, value]) => - url.includes(':' + name) ? accum : { ...accum, [name]: value }, - {} - ); +const removePathParams = (url, params, encode) => + Object.entries(params) + .filter(([key, value]) => value !== undefined) + .reduce( + (accum, [name, value]) => + url.includes(':' + name) + ? accum + : { ...accum, [name]: encode ? encodeURIComponent(value) : value }, + {} + ); const parseQueryParamsFromPagingLink = (link) => { const params = new URLSearchParams(link.split('?')[1]); @@ -89,15 +93,18 @@ class ${outputClass} { ${Object.entries(spec.Endpoints) .map(([endpoint, { Name }]) => { const [method, url] = endpoint.split(' '); - const paramsName = method === 'GET' ? 'params' : 'data'; - + const useQueryParams = ['GET', 'DELETE'].includes(method); return ` - ${Name}(${paramsName}, config) { + ${Name}(data, config) { return this.client.request({ ...config, method: '${method}', - ${paramsName}: removePathParams('${url}', ${paramsName}), - url: substituteParams('${url}', ${paramsName}), + ${ + useQueryParams + ? `params: removePathParams('${url}', data, true),` + : `data: removePathParams('${url}', data, false),` + } + url: substituteParams('${url}', data), }) } `; diff --git a/src/integration.axios.test.ts b/src/integration.axios.test.ts index 186d650..6b387dc 100644 --- a/src/integration.axios.test.ts +++ b/src/integration.axios.test.ts @@ -143,6 +143,34 @@ describe('integration tests', () => { }); }); + test('generated code URI-encodes query parameters', async () => { + const { client, request } = await prepare(); + + await client.listPosts({ filter: 'some/evil/string' }); + + expect(request).toHaveBeenCalledTimes(1); + expect(request).toHaveBeenCalledWith({ + method: 'GET', + url: '/posts/list', + params: { + filter: 'some%2Fevil%2Fstring', + }, + }); + }); + + test('generated code does not send undefined query parameters', async () => { + const { client, request } = await prepare(); + + await client.listPosts({ filter: undefined }); + + expect(request).toHaveBeenCalledTimes(1); + expect(request).toHaveBeenCalledWith({ + method: 'GET', + url: '/posts/list', + params: {}, + }); + }); + test('pagination', async () => { const { client, request } = await prepare();