Skip to content

Commit d155606

Browse files
jbl428imdudu1
andcommitted
feat: add supports for override default http config
Co-authored-by: imdudu1 <cd80@kakao.com>
1 parent 9d36b66 commit d155606

File tree

8 files changed

+77
-22
lines changed

8 files changed

+77
-22
lines changed

lib/builders/http-request.builder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
REQUEST_HEADER_METADATA,
1111
REQUEST_PARAM_METADATA,
1212
} from '../decorators';
13-
import { type HttpMethod } from '../types';
13+
import { type HttpClientOptions, type HttpMethod } from '../types';
1414

1515
export class HttpRequestBuilder {
1616
private baseUrl = '';
@@ -25,6 +25,7 @@ export class HttpRequestBuilder {
2525
readonly method: HttpMethod,
2626
readonly url: string,
2727
readonly gqlQuery?: string,
28+
readonly options?: HttpClientOptions,
2829
) {
2930
this.pathVariableBuilder = this.getMetadata(PATH_VARIABLE_METADATA);
3031
this.requestParamBuilder = this.getMetadata(REQUEST_PARAM_METADATA);

lib/decorators/graphql-exchange.decorator.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import { HTTP_EXCHANGE_METADATA } from './constants';
22
import { HttpRequestBuilder } from '../builders/http-request.builder';
3-
import { type AsyncFunction } from '../types';
3+
import { type AsyncFunction, type HttpClientOptions } from '../types';
44

5-
export function GraphQLExchange(query: string, url = '/graphql') {
5+
export function GraphQLExchange(
6+
query: string,
7+
url = '/graphql',
8+
options?: HttpClientOptions,
9+
) {
610
return <P extends string>(
711
target: Record<P, AsyncFunction>,
812
propertyKey: P,
913
) => {
1014
Reflect.defineMetadata(
1115
HTTP_EXCHANGE_METADATA,
12-
new HttpRequestBuilder(target, propertyKey, 'POST', url, query),
16+
new HttpRequestBuilder(target, propertyKey, 'POST', url, query, options),
1317
target,
1418
propertyKey,
1519
);
Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
import { HTTP_EXCHANGE_METADATA } from './constants';
22
import { HttpRequestBuilder } from '../builders/http-request.builder';
3-
import { type AsyncFunction, type HttpMethod } from '../types';
3+
import {
4+
type AsyncFunction,
5+
type HttpClientOptions,
6+
type HttpMethod,
7+
} from '../types';
48

59
export const HttpExchange =
6-
(method: HttpMethod, url: string) =>
10+
(method: HttpMethod, url: string, options?: HttpClientOptions) =>
711
<P extends string>(target: Record<P, AsyncFunction>, propertyKey: P) => {
812
Reflect.defineMetadata(
913
HTTP_EXCHANGE_METADATA,
10-
new HttpRequestBuilder(target, propertyKey, method, url),
14+
new HttpRequestBuilder(
15+
target,
16+
propertyKey,
17+
method,
18+
url,
19+
undefined,
20+
options,
21+
),
1122
target,
1223
propertyKey,
1324
);
1425
};
1526

1627
/* eslint-disable @typescript-eslint/explicit-function-return-type */
17-
export const GetExchange = (url = '') => HttpExchange('GET', url);
18-
export const PostExchange = (url = '') => HttpExchange('POST', url);
19-
export const PutExchange = (url = '') => HttpExchange('PUT', url);
20-
export const DeleteExchange = (url = '') => HttpExchange('DELETE', url);
21-
export const PatchExchange = (url = '') => HttpExchange('PATCH', url);
22-
export const HeadExchange = (url = '') => HttpExchange('HEAD', url);
23-
export const OptionsExchange = (url = '') => HttpExchange('OPTIONS', url);
28+
export const GetExchange = (url = '', options?: HttpClientOptions) =>
29+
HttpExchange('GET', url, options);
30+
export const PostExchange = (url = '', options?: HttpClientOptions) =>
31+
HttpExchange('POST', url, options);
32+
export const PutExchange = (url = '', options?: HttpClientOptions) =>
33+
HttpExchange('PUT', url, options);
34+
export const DeleteExchange = (url = '', options?: HttpClientOptions) =>
35+
HttpExchange('DELETE', url, options);
36+
export const PatchExchange = (url = '', options?: HttpClientOptions) =>
37+
HttpExchange('PATCH', url, options);
38+
export const HeadExchange = (url = '', options?: HttpClientOptions) =>
39+
HttpExchange('HEAD', url, options);
40+
export const OptionsExchange = (url = '', options?: HttpClientOptions) =>
41+
HttpExchange('OPTIONS', url, options);

lib/fixtures/stub-http-client.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { type HttpClient } from '../types/http-client.interface';
1+
import { type HttpClient, type HttpClientOptions } from '../types';
22

33
export class StubHttpClient implements HttpClient {
44
#requestInfo: Request[] = [];
55
#responses: Response[] = [];
6+
#options: Array<HttpClientOptions | undefined> = [];
67

7-
async request(request: Request): Promise<Response> {
8+
async request(
9+
request: Request,
10+
options?: HttpClientOptions,
11+
): Promise<Response> {
812
this.#requestInfo.push(request);
13+
this.#options.push(options);
914

1015
const response = this.#responses.shift();
1116

@@ -16,6 +21,10 @@ export class StubHttpClient implements HttpClient {
1621
return this.#requestInfo;
1722
}
1823

24+
get options(): Array<HttpClientOptions | undefined> {
25+
return this.#options;
26+
}
27+
1928
addResponse(body: Record<string, unknown> | string): void {
2029
const response = new Response(JSON.stringify(body));
2130
this.#responses.push(response);

lib/supports/fetch-http-client.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,19 @@ describe('FetchHttpClient', () => {
109109
// then
110110
await expect(doRequest).rejects.toThrowError('Request Timeout: 3000ms');
111111
});
112+
113+
test('should use given option if provided', async () => {
114+
// given
115+
const address = fastify.server.address() as AddressInfo;
116+
const httpClient = new FetchHttpClient(60000);
117+
const request = new Request(`http://localhost:${address.port}/timeout`);
118+
const httpClientOptions = { timeout: 300 };
119+
120+
// when
121+
const doRequest = async (): Promise<Response> =>
122+
await httpClient.request(request, httpClientOptions);
123+
124+
// then
125+
await expect(doRequest).rejects.toThrowError('Request Timeout: 300ms');
126+
});
112127
});

lib/supports/fetch-http-client.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type HttpClient } from '../types';
1+
import { type HttpClient, type HttpClientOptions } from '../types';
22

33
export class FetchHttpClient implements HttpClient {
44
readonly #timeout: number;
@@ -7,16 +7,20 @@ export class FetchHttpClient implements HttpClient {
77
this.#timeout = timeout;
88
}
99

10-
async request(request: Request): Promise<Response> {
10+
async request(
11+
request: Request,
12+
options?: HttpClientOptions,
13+
): Promise<Response> {
1114
const controller = new AbortController();
15+
const timeout = options?.timeout ?? this.#timeout;
1216

1317
return await Promise.race<Response>([
1418
fetch(request, { signal: controller.signal }),
1519
new Promise((resolve, reject) =>
1620
setTimeout(() => {
1721
controller.abort();
18-
reject(new Error(`Request Timeout: ${this.#timeout}ms`));
19-
}, this.#timeout),
22+
reject(new Error(`Request Timeout: ${timeout}ms`));
23+
}, timeout),
2024
),
2125
]);
2226
}

lib/supports/node-fetch.injector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class NodeFetchInjector implements OnModuleInit {
4949

5050
wrapper.instance[methodName] = async (...args: never[]) =>
5151
await this.httpClient
52-
.request(httpRequestBuilder.build(args))
52+
.request(httpRequestBuilder.build(args), httpRequestBuilder.options)
5353
.then(async (response) => {
5454
if (responseBodyBuilder != null) {
5555
const res = await response.json();

lib/types/http-client.interface.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { type HttpInterfaceConfig } from '../http-interface.module';
2+
3+
export type HttpClientOptions = Omit<HttpInterfaceConfig, 'httpClient'>;
4+
15
export interface HttpClient {
2-
request: (request: Request) => Promise<Response>;
6+
request: (request: Request, options?: HttpClientOptions) => Promise<Response>;
37
}

0 commit comments

Comments
 (0)