2
2
const { apiConfig, generateResponses } = it;
3
3
%>
4
4
5
- export type RequestParams = Omit<RequestInit, "body" | "method"> & {
6
- secure?: boolean;
5
+ export type QueryParamsType = Record<string | number, any>;
6
+ export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
7
+
8
+ export interface FullRequestParams extends Omit<RequestInit, "body"> {
9
+ /** set parameter to `true` for call `securityWorker` for this request */
10
+ secure?: boolean;
11
+ /** request path */
12
+ path: string;
13
+ /** content type of request body */
14
+ type?: ContentType;
15
+ /** query params */
16
+ query?: QueryParamsType;
17
+ /** format of response (i.e. response.json() -> format: "json") */
18
+ format?: keyof Omit<Body, "body" | "bodyUsed">;
19
+ /** request body */
20
+ body?: unknown;
21
+ /** base url */
22
+ baseUrl?: string;
7
23
}
8
24
9
- export type RequestQueryParamsType = Record<string | number, any>;
25
+ export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">
10
26
11
27
12
28
interface ApiConfig<<%~ apiConfig.generic.map(g => g.name).join(', ') %>> {
13
29
baseUrl?: string;
14
- baseApiParams?: RequestParams;
30
+ baseApiParams?: Omit< RequestParams, "baseUrl"> ;
15
31
securityWorker?: (securityData: SecurityDataType) => RequestParams;
16
32
}
17
33
@@ -28,10 +44,10 @@ interface HttpResponse<D extends unknown, E extends unknown = unknown> extends R
28
44
error: E;
29
45
}
30
46
31
- enum BodyType {
32
- Json,
33
- FormData,
34
- UrlEncoded,
47
+ export enum ContentType {
48
+ Json = "application/json" ,
49
+ FormData = "multipart/form-data" ,
50
+ UrlEncoded = "application/x-www-form-urlencoded" ,
35
51
}
36
52
37
53
export class HttpClient<<%~ apiConfig.generic.map(g => `${g.name} = unknown`).join(', ') %>> {
@@ -42,7 +58,7 @@ export class HttpClient<<%~ apiConfig.generic.map(g => `${g.name} = unknown`).jo
42
58
private baseApiParams: RequestParams = {
43
59
credentials: 'same-origin',
44
60
headers: {
45
- 'Content-Type': 'application/json'
61
+ 'Content-Type': ContentType.Json
46
62
},
47
63
redirect: 'follow',
48
64
referrerPolicy: 'no-referrer',
@@ -56,91 +72,103 @@ export class HttpClient<<%~ apiConfig.generic.map(g => `${g.name} = unknown`).jo
56
72
this.securityData = data
57
73
}
58
74
59
- private addQueryParam(query: RequestQueryParamsType, key: string) {
60
- return encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key])
75
+ private addQueryParam(query: QueryParamsType, key: string) {
76
+ const value = query[key];
77
+
78
+ return (
79
+ encodeURIComponent(key) + "=" + encodeURIComponent(
80
+ Array.isArray(value) ? value.join(",") :
81
+ typeof value === "number" ? value :
82
+ `${value}`
83
+ )
84
+ );
61
85
}
62
86
63
- protected toQueryString(rawQuery?: RequestQueryParamsType ): string {
87
+ protected toQueryString(rawQuery?: QueryParamsType ): string {
64
88
const query = rawQuery || {};
65
89
const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
66
90
return keys
67
91
.map((key) =>
68
92
typeof query[key] === "object" && !Array.isArray(query[key])
69
- ? this.toQueryString(query[key] as object )
93
+ ? this.toQueryString(query[key] as QueryParamsType )
70
94
: this.addQueryParam(query, key),
71
95
)
72
96
.join("&");
73
97
}
74
98
75
- protected addQueryParams(rawQuery?: RequestQueryParamsType ): string {
99
+ protected addQueryParams(rawQuery?: QueryParamsType ): string {
76
100
const queryString = this.toQueryString(rawQuery);
77
101
return queryString ? `?${queryString}` : "";
78
102
}
79
103
80
- private bodyFormatters : Record<BodyType , (input: any) => any> = {
81
- [BodyType .Json]: JSON.stringify,
82
- [BodyType .FormData]: (input: any) =>
104
+ private contentFormatters : Record<ContentType , (input: any) => any> = {
105
+ [ContentType .Json]: JSON.stringify,
106
+ [ContentType .FormData]: (input: any) =>
83
107
Object.keys(input).reduce((data, key) => {
84
108
data.append(key, input[key]);
85
109
return data;
86
110
}, new FormData()),
87
- [BodyType .UrlEncoded]: (input: any) => this.toQueryString(input),
111
+ [ContentType .UrlEncoded]: (input: any) => this.toQueryString(input),
88
112
}
89
113
90
- private mergeRequestOptions(params : RequestParams, securityParams ?: RequestParams): RequestParams {
114
+ private mergeRequestParams(params1 : RequestParams, params2 ?: RequestParams): RequestParams {
91
115
return {
92
116
...this.baseApiParams,
93
- ...params ,
94
- ...(securityParams || {}),
117
+ ...params1 ,
118
+ ...(params2 || {}),
95
119
headers: {
96
120
...(this.baseApiParams.headers || {}),
97
- ...(params .headers || {}),
98
- ...((securityParams && securityParams .headers) || {})
99
- }
100
- }
121
+ ...(params1 .headers || {}),
122
+ ...((params2 && params2 .headers) || {}),
123
+ },
124
+ };
101
125
}
102
-
103
- private safeParseResponse = <T = any, E = any>(response: Response): Promise<HttpResponse<T, E>> => {
104
- const r = response as HttpResponse<T, E>;
105
- r.data = null as unknown as T;
106
- r.error = null as unknown as E;
107
-
108
- return response
109
- .json()
110
- .then((data) => {
111
- if (r.ok) {
112
- r.data = data;
113
- } else {
114
- r.error = data;
115
- }
116
- return r;
117
- })
118
- .catch((e) => {
119
- r.error = e;
120
- return r;
121
- });
122
- }
123
-
124
- public request = <T = any, E = any>(
125
- path: string,
126
- method: string,
127
- { secure, ...params }: RequestParams = {},
128
- body?: any,
129
- bodyType?: BodyType,
130
- secureByDefault?: boolean,
131
- ): <% if (generateResponses) { %>TPromise<HttpResponse<T, E>><% } else { %>Promise<HttpResponse<T>><% } %> => {
132
- const requestUrl = `${this.baseUrl}${path}`;
133
- const secureOptions = (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {};
134
- const requestOptions = {
135
- ...this.mergeRequestOptions(params, secureOptions),
136
- method,
137
- body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null,
126
+
127
+ public request = <T = any, E = any>({
128
+ body,
129
+ secure,
130
+ path,
131
+ type = ContentType.Json,
132
+ query,
133
+ format = "json",
134
+ baseUrl,
135
+ ...params
136
+ }: FullRequestParams): <% if (generateResponses) { %>TPromise<HttpResponse<T, E>><% } else { %>Promise<HttpResponse<T, E>><% } %> => {
137
+ const secureParams = (secure && this.securityWorker) ? this.securityWorker(this.securityData) : {};
138
+ const requestParams = this.mergeRequestParams(params, secureParams);
139
+ const queryString = query && this.toQueryString(query);
140
+
141
+ return fetch(
142
+ `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`,
143
+ {
144
+ headers: {
145
+ "Content-Type": type,
146
+ ...(requestParams.headers || {}),
147
+ },
148
+ ...requestParams,
149
+ body: body ? (this.contentFormatters[type] ? this.contentFormatters[type](body) : body) : null,
138
150
}
139
-
140
- return fetch(requestUrl, requestOptions).then(async response => {
141
- const data = await this.safeParseResponse<T, E>(response);
142
- if (!response.ok) throw data
143
- return data
144
- })
145
- }
151
+ ).then(async (response) => {
152
+ const r = response as HttpResponse<T, E>;
153
+ r.data = (null as unknown) as T;
154
+ r.error = (null as unknown) as E;
155
+
156
+ const data = await response[format]()
157
+ .then((data) => {
158
+ if (r.ok) {
159
+ r.data = data;
160
+ } else {
161
+ r.error = data;
162
+ }
163
+ return r;
164
+ })
165
+ .catch((e) => {
166
+ r.error = e;
167
+ return r;
168
+ });
169
+
170
+ if (!response.ok) throw data;
171
+ return data;
172
+ });
173
+ };
146
174
}
0 commit comments