diff --git a/src/api/request-fetcher/index.spec.tsx b/src/api/request-fetcher/index.spec.tsx index a3a5a75..0c8f3d3 100644 --- a/src/api/request-fetcher/index.spec.tsx +++ b/src/api/request-fetcher/index.spec.tsx @@ -19,7 +19,12 @@ it('parses application/json with charset', async () => { url: 'http://test.com/endpoint', method: 'GET' }) - ).toEqual({body: {num: 12345}, bodyType: 'json', status: 200}) + ).toEqual({ + body: {num: 12345}, + bodyType: 'json', + status: 200, + headers: new Headers({'content-type': 'application/json; charset=utf-8'}) + }) }) it('does not parse the response body if it cant determine the response type', async () => { @@ -32,7 +37,14 @@ it('does not parse the response body if it cant determine the response type', as url: 'http://test.com/endpoint', method: 'GET' }) - ).toEqual({status: 200, body: null, bodyType: null}) + ).toEqual({ + status: 200, + body: null, + bodyType: null, + headers: new Headers({ + 'Content-Type': '' + }) + }) // unknown content type fetchMock.mockResponseOnce(JSON.stringify({num: 12345}), { @@ -43,7 +55,12 @@ it('does not parse the response body if it cant determine the response type', as url: 'http://test.com/endpoint', method: 'GET' }) - ).toEqual({status: 200, body: null, bodyType: null}) + ).toEqual({ + status: 200, + body: null, + bodyType: null, + headers: new Headers({'Content-Type': 'unknown'}) + }) }) it('throws a TypeError if an invalid body is passed', async () => { diff --git a/src/api/request-fetcher/index.tsx b/src/api/request-fetcher/index.tsx index 3b26e57..9c3129b 100644 --- a/src/api/request-fetcher/index.tsx +++ b/src/api/request-fetcher/index.tsx @@ -31,16 +31,14 @@ export class ApiRequestFetcher implements RequestFetcher { response: Response, params: RequestFetcherParams ): Promise { - const {status} = response + const {status, headers} = response const responseType = params.responseType || - this.inferResponseTypeUsingContentType( - response.headers.get('Content-Type') - ) + this.inferResponseTypeUsingContentType(headers.get('Content-Type')) if (!responseType) { - return {body: null, bodyType: null, status} + return {body: null, bodyType: null, status, headers} } const body = await (() => { @@ -56,7 +54,7 @@ export class ApiRequestFetcher implements RequestFetcher { } })() - return {body: body, bodyType: responseType, status} + return {body: body, bodyType: responseType, status, headers} } /** diff --git a/src/api/request-manager/index.tsx b/src/api/request-manager/index.tsx index 35ec395..a63a081 100644 --- a/src/api/request-manager/index.tsx +++ b/src/api/request-manager/index.tsx @@ -178,6 +178,10 @@ export class ApiRequestManager { successCodes: params.successCodes }) + if (params.method === 'HEAD') { + return response.headers + } + const parsedResponse: RequestFetcherResponse = { ...response, body: diff --git a/src/api/typings.tsx b/src/api/typings.tsx index 33a5649..2eb1dd9 100644 --- a/src/api/typings.tsx +++ b/src/api/typings.tsx @@ -1,12 +1,21 @@ -export type ApiRequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' +export type ApiRequestMethod = + | 'GET' + | 'HEAD' + | 'POST' + | 'PUT' + | 'PATCH' + | 'DELETE' export type ApiHeaders = Record -type GetDeleteRequestMethod = Extract +type GetDeleteRequestMethod = Extract< + ApiRequestMethod, + 'GET' | 'HEAD' | 'DELETE' +> type PostPutPatchRequestMethod = Extract< ApiRequestMethod, 'POST' | 'PUT' | 'PATCH' > export type RequestBody = BodyInit | object -export type ResponseBody = Blob | object | string +export type ResponseBody = Blob | object | string | Headers export type ApiResponseType = 'json' | 'text' | 'blob' interface ApiCommonRequestParams { @@ -110,4 +119,5 @@ export interface RequestFetcherResponse { body: ResponseBody | null bodyType: ApiResponseType | null status: number + headers: Headers } diff --git a/src/endpoints/index.spec.tsx b/src/endpoints/index.spec.tsx index bf2951d..b1b0628 100644 --- a/src/endpoints/index.spec.tsx +++ b/src/endpoints/index.spec.tsx @@ -9,6 +9,10 @@ describe('HttpEndpoints', () => { class Endpoints extends HttpEndpoints { static basePath = '/base' + static HEAD(init: Omit) { + return super._head('/endpoint', init) + } + static GET(init: Omit) { return super._get('/endpoint', init) } @@ -31,7 +35,7 @@ describe('HttpEndpoints', () => { } test('endpoints by method', () => { - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]()).toEqual({ method, url: '/base/endpoint' @@ -54,7 +58,7 @@ describe('HttpEndpoints', () => { test('request headers', () => { const headers = {test: 'body'} - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]({headers})).toEqual({ method, url: '/base/endpoint', @@ -73,7 +77,7 @@ describe('HttpEndpoints', () => { zero: 0 } - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]({query})).toEqual({ method, url: '/base/endpoint?empty=&null=null&num=3&str=string&zero=0' @@ -85,7 +89,7 @@ describe('HttpEndpoints', () => { }) test('extra key', () => { - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]({extraKey: 'test'})).toEqual({ method, url: '/base/endpoint', @@ -98,7 +102,7 @@ describe('HttpEndpoints', () => { test('applying trailing slash to each url', () => { ;(Endpoints as any).trailingSlash = true - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]()).toEqual({ method, url: '/base/endpoint/' @@ -111,7 +115,7 @@ describe('HttpEndpoints', () => { test('applying trailing slash to each url', () => { ;(Endpoints as any).trailingSlash = true - for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { + for (const method of ['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { expect(Endpoints[method]()).toEqual({ method, url: '/base/endpoint/' diff --git a/src/endpoints/index.tsx b/src/endpoints/index.tsx index baa147b..758dd83 100644 --- a/src/endpoints/index.tsx +++ b/src/endpoints/index.tsx @@ -46,6 +46,19 @@ export class HttpEndpoints { return builtPath } + /** + * Creates a `HEAD` request. + * + * @param path A path relative to the base path. + * @param requestInit Additional request parameters. + */ + protected static _head( + path: string, + requestInit?: Omit + ) { + return this._createRequest<'HEAD', TResponseBody>('HEAD', path, requestInit) + } + /** * Creates a `GET` request. *