Skip to content

FRON-5083 Add Head Request to Fairlight #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
23 changes: 20 additions & 3 deletions src/api/request-fetcher/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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}), {
Expand All @@ -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 () => {
Expand Down
10 changes: 4 additions & 6 deletions src/api/request-fetcher/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,14 @@ export class ApiRequestFetcher implements RequestFetcher {
response: Response,
params: RequestFetcherParams
): Promise<RequestFetcherResponse> {
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 (() => {
Expand All @@ -56,7 +54,7 @@ export class ApiRequestFetcher implements RequestFetcher {
}
})()

return {body: body, bodyType: responseType, status}
return {body: body, bodyType: responseType, status, headers}
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/api/request-manager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ export class ApiRequestManager {
successCodes: params.successCodes
})

if (params.method === 'HEAD') {
return response.headers
}

const parsedResponse: RequestFetcherResponse = {
...response,
body:
Expand Down
16 changes: 13 additions & 3 deletions src/api/typings.tsx
Original file line number Diff line number Diff line change
@@ -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<string, string>
type GetDeleteRequestMethod = Extract<ApiRequestMethod, 'GET' | 'DELETE'>
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<TMethod extends ApiRequestMethod> {
Expand Down Expand Up @@ -110,4 +119,5 @@ export interface RequestFetcherResponse {
body: ResponseBody | null
bodyType: ApiResponseType | null
status: number
headers: Headers
}
16 changes: 10 additions & 6 deletions src/endpoints/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ describe('HttpEndpoints', () => {
class Endpoints extends HttpEndpoints {
static basePath = '/base'

static HEAD(init: Omit<EndpointCreateRequestInit, 'body'>) {
return super._head('/endpoint', init)
}

static GET(init: Omit<EndpointCreateRequestInit, 'body'>) {
return super._get('/endpoint', init)
}
Expand All @@ -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'
Expand All @@ -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',
Expand All @@ -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'
Expand All @@ -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',
Expand All @@ -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/'
Expand All @@ -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/'
Expand Down
13 changes: 13 additions & 0 deletions src/endpoints/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<TResponseBody extends ResponseBody = ResponseBody>(
path: string,
requestInit?: Omit<EndpointCreateRequestInit, 'body'>
) {
return this._createRequest<'HEAD', TResponseBody>('HEAD', path, requestInit)
}

/**
* Creates a `GET` request.
*
Expand Down