diff --git a/README.md b/README.md index df6907ca..afd1c800 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ type Err = FetchErrorType ### Utility Methods -- `arrayRequestBody` - Helper to merge params when request body is an array +- `arrayRequestBody` - Helper to merge params when request body is an array [see issue](https://github.com/ajaishankar/openapi-typescript-fetch/issues/3#issuecomment-952963986) ```ts diff --git a/package.json b/package.json index 891b4997..02362eca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "openapi-typescript-fetch", "description": "A typed fetch client for openapi-typescript", - "version": "1.1.2", + "version": "1.1.3", "engines": { "node": ">= 12.0.0", "npm": ">= 7.0.0" diff --git a/src/fetcher.ts b/src/fetcher.ts index 6a6af99d..1eb1d5f9 100644 --- a/src/fetcher.ts +++ b/src/fetcher.ts @@ -72,10 +72,10 @@ function getQuery( return queryString(queryObj) } -function getHeaders(init?: HeadersInit) { +function getHeaders(body?: string, init?: HeadersInit) { const headers = new Headers(init) - if (!headers.has('Content-Type')) { + if (body !== undefined && !headers.has('Content-Type')) { headers.append('Content-Type', 'application/json') } @@ -120,14 +120,15 @@ function getFetchParams(request: Request) { const path = getPath(request.path, payload) const query = getQuery(request.method, payload, request.queryParams) - const headers = getHeaders(request.init?.headers) + const body = getBody(request.method, payload) + const headers = getHeaders(body, request.init?.headers) const url = request.baseUrl + path + query const init = { ...request.init, method: request.method.toUpperCase(), headers, - body: getBody(request.method, payload), + body, } return { url, init } @@ -135,6 +136,9 @@ function getFetchParams(request: Request) { async function getResponseData(response: Response) { const contentType = response.headers.get('content-type') + if (response.status === 204 /* no content */) { + return undefined + } if (contentType && contentType.indexOf('application/json') !== -1) { return await response.json() } @@ -179,7 +183,6 @@ function wrapMiddlewares(middlewares: Middleware[], fetch: Fetch): Fetch { return fetch(url, init) } const current = middlewares[index] - init = init || { headers: getHeaders() } return await current(url, init, (nextUrl, nextInit) => handler(index + 1, nextUrl, nextInit), ) diff --git a/test/fetch.test.ts b/test/fetch.test.ts index f2f9aa71..974dbdda 100644 --- a/test/fetch.test.ts +++ b/test/fetch.test.ts @@ -24,10 +24,14 @@ describe('fetch', () => { const expectedHeaders = { authorization: 'Bearer token', - 'content-type': 'application/json', accept: 'application/json', } + const headersWithContentType = { + ...expectedHeaders, + 'content-type': 'application/json', + } + it('GET /query/{a}/{b}', async () => { const fun = fetcher.path('/query/{a}/{b}').method('get').create() @@ -60,7 +64,7 @@ describe('fetch', () => { expect(data.params).toEqual({ id: '1' }) expect(data.body).toEqual({ list: ['b', 'c'] }) expect(data.query).toEqual({}) - expect(data.headers).toEqual(expectedHeaders) + expect(data.headers).toEqual(headersWithContentType) }) }) @@ -73,7 +77,7 @@ describe('fetch', () => { expect(data.params).toEqual({ id: '1' }) expect(data.body).toEqual(['b', 'c']) expect(data.query).toEqual({}) - expect(data.headers).toEqual(expectedHeaders) + expect(data.headers).toEqual(headersWithContentType) }) }) @@ -93,10 +97,27 @@ describe('fetch', () => { expect(data.params).toEqual({ id: '1' }) expect(data.body).toEqual({ list: ['b', 'c'] }) expect(data.query).toEqual({ scalar: 'a' }) - expect(data.headers).toEqual(expectedHeaders) + expect(data.headers).toEqual(headersWithContentType) }) }) + it(`DELETE /body/{id} (empty body)`, async () => { + const fun = fetcher.path('/body/{id}').method('delete').create() + + const { data } = await fun({ id: 1 } as any) + + expect(data.params).toEqual({ id: '1' }) + expect(data.headers).toHaveProperty('accept') + expect(data.headers).not.toHaveProperty('content-type') + }) + + it(`POST /nocontent`, async () => { + const fun = fetcher.path('/nocontent').method('post').create() + const { status, data } = await fun(undefined) + expect(status).toBe(204) + expect(data).toBeUndefined() + }) + it('GET /error', async () => { expect.assertions(3) diff --git a/test/mocks/handlers.ts b/test/mocks/handlers.ts index 9cd2163a..1ea77152 100644 --- a/test/mocks/handlers.ts +++ b/test/mocks/handlers.ts @@ -64,6 +64,9 @@ const methods = { ) : res(ctx.status(status)) }), + rest.post(`${HOST}/nocontent`, (req, res, ctx) => { + return res(ctx.status(204)) + }), rest.get(`${HOST}/defaulterror`, (req, res, ctx) => { return res(ctx.status(500), ctx.body('internal server error')) }), diff --git a/test/paths.ts b/test/paths.ts index f673296f..afc3831a 100644 --- a/test/paths.ts +++ b/test/paths.ts @@ -61,6 +61,14 @@ export type paths = { patch: BodyAndQuery delete: BodyAndQuery } + '/nocontent': { + post: { + parameters: {} + responses: { + 204: unknown + } + } + } '/error/{status}': { get: { parameters: {