2
2
const { apiConfig , generateResponses , config } = it;
3
3
%>
4
4
5
- import type { KyInstance, Options as KyOptions, SearchParamsOption } from "ky";
5
+ import type {
6
+ BeforeRequestHook,
7
+ Hooks,
8
+ KyInstance,
9
+ Options as KyOptions,
10
+ NormalizedOptions,
11
+ SearchParamsOption,
12
+ } from "ky";
6
13
import ky from "ky";
7
14
8
15
type KyResponse<Data > = Response & {
@@ -19,7 +26,10 @@ export type ResponsePromise<Data> = {
19
26
20
27
export type ResponseFormat = keyof Omit<Body , " body" | " bodyUsed" >;
21
28
22
- export interface FullRequestParams extends Omit<KyOptions , " json" | " body" | " searchParams" > {
29
+ export interface FullRequestParams
30
+ extends Omit<KyOptions , " json" | " body" | " searchParams" > {
31
+ /** set parameter to `true` for call `securityWorker` for this request */
32
+ secure?: boolean;
23
33
/** request path */
24
34
path: string;
25
35
/** content type of request body */
@@ -32,9 +42,17 @@ export interface FullRequestParams extends Omit<KyOptions, "json" | "body" | "se
32
42
body?: unknown;
33
43
}
34
44
35
- export type RequestParams = Omit<FullRequestParams , " body" | " method" | " query" | " path" >;
36
-
37
- export interface ApiConfig<SecurityDataType = unknown > extends Omit<KyOptions , " data" | " cancelToken" > {
45
+ export type RequestParams = Omit<
46
+ FullRequestParams,
47
+ "body" | "method" | "query" | "path"
48
+ >;
49
+
50
+ export interface ApiConfig<SecurityDataType = unknown >
51
+ extends Omit<KyOptions , " data" | " cancelToken" > {
52
+ securityWorker?: (
53
+ securityData: SecurityDataType | null,
54
+ ) => Promise<NormalizedOptions | void > | NormalizedOptions | void;
55
+ secure?: boolean;
38
56
format?: ResponseType;
39
57
}
40
58
@@ -46,92 +64,152 @@ export enum ContentType {
46
64
}
47
65
48
66
export class HttpClient<SecurityDataType = unknown > {
49
- public ky: KyInstance;
50
- private format?: ResponseType;
67
+ public ky: KyInstance;
68
+ private securityData: SecurityDataType | null = null;
69
+ private securityWorker?: ApiConfig<SecurityDataType >["securityWorker"];
70
+ private secure?: boolean;
71
+ private format?: ResponseType;
72
+
73
+ constructor({
74
+ securityWorker,
75
+ secure,
76
+ format,
77
+ ...options
78
+ }: ApiConfig<SecurityDataType > = {}) {
79
+ this.ky = ky.create({ ...options, prefixUrl: options.prefixUrl || "" });
80
+ this.secure = secure;
81
+ this.format = format;
82
+ this.securityWorker = securityWorker;
83
+ }
84
+
85
+ public setSecurityData = (data: SecurityDataType | null) => {
86
+ this.securityData = data;
87
+ };
88
+
89
+ protected mergeRequestParams(
90
+ params1: KyOptions,
91
+ params2?: KyOptions,
92
+ ): KyOptions {
93
+ return {
94
+ ...params1,
95
+ ...params2,
96
+ headers: {
97
+ ...params1.headers,
98
+ ...(params2 && params2.headers),
99
+ },
100
+ };
101
+ }
51
102
52
- constructor({ format, ...options }: ApiConfig<SecurityDataType > = {}) {
53
- this.ky = ky.create({ ...options, prefixUrl: options.prefixUrl || "<% ~ apiConfig .baseUrl %> " })
54
- this.format = format;
103
+ protected stringifyFormItem(formItem: unknown) {
104
+ if (typeof formItem === "object" && formItem !== null) {
105
+ return JSON.stringify(formItem);
106
+ } else {
107
+ return `${formItem}`;
55
108
}
56
-
57
- protected stringifyFormItem(formItem: unknown) {
58
- if (typeof formItem === "object" && formItem !== null) {
59
- return JSON.stringify(formItem);
60
- } else {
61
- return `${formItem}`;
109
+ }
110
+
111
+ protected createFormData(input: Record<string , unknown >): FormData {
112
+ return Object.keys(input || {}).reduce((formData, key) => {
113
+ const property = input[key];
114
+ const propertyContent: any[] =
115
+ property instanceof Array ? property : [property];
116
+
117
+ for (const formItem of propertyContent) {
118
+ const isFileType = formItem instanceof Blob || formItem instanceof File;
119
+ formData.append(
120
+ key,
121
+ isFileType ? formItem : this.stringifyFormItem(formItem),
122
+ );
62
123
}
63
- }
64
-
65
- protected createFormData(input: Record<string , unknown >): FormData {
66
- return Object.keys(input || {}).reduce((formData, key) => {
67
- const property = input[key];
68
- const propertyContent: any[] = (property instanceof Array) ? property : [property]
69
-
70
- for (const formItem of propertyContent) {
71
- const isFileType = formItem instanceof Blob || formItem instanceof File;
72
- formData.append(
73
- key,
74
- isFileType ? formItem : this.stringifyFormItem(formItem)
75
- );
76
- }
77
-
78
- return formData;
79
- }, new FormData());
80
- }
81
124
82
- public request = <T = any, _E = any >({
83
- path,
84
- type,
85
- query,
86
- format,
87
- body,
88
- ...options
125
+ return formData;
126
+ }, new FormData());
127
+ }
128
+
129
+ public request = <T = any, _E = any >({
130
+ secure = this.secure,
131
+ path,
132
+ type,
133
+ query,
134
+ format,
135
+ body,
136
+ ...options
89
137
<% if (config .unwrapResponseData ) { % >
90
- }: FullRequestParams): Promise < T > => {
138
+ }: FullRequestParams): Promise < T > => {
91
139
< % } else { % >
92
- }: FullRequestParams): ResponsePromise< T > => {
140
+ }: FullRequestParams): ResponsePromise< T > => {
93
141
< % } %>
94
- if (body) {
95
- if (type === ContentType.FormData) {
96
- body = typeof body === "object" ? this.createFormData(body as Record<string , unknown >) : body;
97
- } else if (type === ContentType.Text) {
98
- body = typeof body !== "string" ? JSON.stringify(body) : body;
99
- }
100
- }
142
+ if (body) {
143
+ if (type === ContentType.FormData) {
144
+ body =
145
+ typeof body === "object"
146
+ ? this.createFormData(body as Record<string , unknown >)
147
+ : body;
148
+ } else if (type === ContentType.Text) {
149
+ body = typeof body !== "string" ? JSON.stringify(body) : body;
150
+ }
151
+ }
101
152
102
- let headers: Headers | Record<string , string | undefined > | undefined;
103
- if (options.headers instanceof Headers) {
104
- headers = new Headers(options.headers);
105
- if (type && type !== ContentType.FormData) {
106
- headers.set('Content-Type', type);
107
- }
108
- } else {
109
- headers = { ...options.headers } as Record<string , string | undefined >;
110
- if (type && type !== ContentType.FormData) {
111
- headers['Content-Type'] = type;
153
+ let headers: Headers | Record<string , string | undefined > | undefined;
154
+ if (options.headers instanceof Headers) {
155
+ headers = new Headers(options.headers);
156
+ if (type && type !== ContentType.FormData) {
157
+ headers.set("Content-Type", type);
158
+ }
159
+ } else {
160
+ headers = { ...options.headers } as Record<string , string | undefined >;
161
+ if (type && type !== ContentType.FormData) {
162
+ headers["Content-Type"] = type;
163
+ }
164
+ }
165
+
166
+ let hooks: Hooks | undefined;
167
+ if (secure && this.securityWorker) {
168
+ const securityWorker: BeforeRequestHook = async (_request, options) => {
169
+ const secureOptions = await this.securityWorker!(this.securityData);
170
+ if (secureOptions && typeof secureOptions === "object") {
171
+ const headers = new Headers(options.headers);
172
+ if (secureOptions && secureOptions.headers) {
173
+ const secureHeaders = new Headers(secureOptions.headers);
174
+ secureHeaders.forEach((value, key) => {
175
+ headers.set(key, value);
176
+ });
112
177
}
178
+ Object.assign(options, secureOptions);
179
+ options.headers = headers;
113
180
}
181
+ };
182
+
183
+ hooks = {
184
+ ...options.hooks,
185
+ beforeRequest:
186
+ options.hooks && options.hooks.beforeRequest
187
+ ? [securityWorker, ...options.hooks.beforeRequest]
188
+ : [securityWorker],
189
+ };
190
+ }
114
191
115
- const request = this.ky(path.replace(/^\//, ''), {
116
- ...options,
117
- headers,
118
- searchParams: query,
119
- body: body as any,
120
- });
192
+ const request = this.ky(path.replace(/^\//, ""), {
193
+ ...options,
194
+ headers,
195
+ searchParams: query,
196
+ body: body as any,
197
+ hooks,
198
+ });
121
199
122
200
<% if (config .unwrapResponseData ) { % >
123
- const responseFormat = ( format || this .format ) || undefined ;
124
- return responseFormat === " json"
125
- ? request .json ()
126
- : responseFormat === " arrayBuffer"
127
- ? request .arrayBuffer ()
128
- : responseFormat === " blob"
201
+ const responseFormat = format || this .format || undefined ;
202
+ return ( responseFormat === " json"
203
+ ? request .json ()
204
+ : responseFormat === " arrayBuffer"
205
+ ? request .arrayBuffer ()
206
+ : responseFormat === " blob"
129
207
? request .blob ()
130
208
: responseFormat === " formData"
131
- ? request .formData ()
132
- : request .text ();
209
+ ? request .formData ()
210
+ : request .text ()) as Promise < T > ;
133
211
< % } else { % >
134
- return request;
212
+ return request;
135
213
< % } %>
136
- };
214
+ };
137
215
}
0 commit comments