@compassdigital/sdk.typescript 3.0.0-beta.10 → 3.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -8
- package/gen.ts +11 -4
- package/lib/base.d.ts +108 -6
- package/lib/base.d.ts.map +1 -1
- package/lib/base.js +152 -28
- package/lib/base.js.map +1 -1
- package/lib/index.d.ts +236 -236
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/order.d.ts +4 -4
- package/lib/order.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/base.ts +148 -15
- package/src/index.ts +273 -238
- package/src/order.ts +6 -6
- package/template.ejs +2 -2
- package/test/client.test.ts +25 -3
- package/test/gen.test.ts +22 -0
package/src/base.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface RequestOptions {
|
|
|
19
19
|
intercept?: InterceptFn;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The request data provided to intercept
|
|
24
|
+
* functions.
|
|
25
|
+
*/
|
|
22
26
|
export interface RequestData {
|
|
23
27
|
name: string;
|
|
24
28
|
service: string;
|
|
@@ -28,23 +32,91 @@ export interface RequestData {
|
|
|
28
32
|
body?: string;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The response data expected from
|
|
37
|
+
* intercept functions.
|
|
38
|
+
*/
|
|
31
39
|
export interface ResponseData {
|
|
32
40
|
ok: boolean;
|
|
33
41
|
status: number;
|
|
34
42
|
body: string;
|
|
35
43
|
}
|
|
36
44
|
|
|
45
|
+
/**
|
|
46
|
+
* A function that performs an https request.
|
|
47
|
+
*/
|
|
37
48
|
export type FetchFn = (req: RequestData) => Promise<ResponseData>;
|
|
38
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A function that intercepts an http request and returns a response.
|
|
52
|
+
*/
|
|
39
53
|
export type InterceptFn = (req: RequestData, fetch: FetchFn) => Promise<ResponseData>;
|
|
40
54
|
|
|
41
|
-
|
|
55
|
+
/**
|
|
56
|
+
* We have to re-implement the promise methods instead of just existing
|
|
57
|
+
* the existing Promise class due to: https://github.com/microsoft/TypeScript/issues/15202
|
|
58
|
+
*/
|
|
59
|
+
export class ResponsePromise<T> implements Promise<T> {
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Implements Promise interface.
|
|
63
|
+
*/
|
|
64
|
+
[Symbol.toStringTag] = "[object ResponsePromise]";
|
|
65
|
+
|
|
66
|
+
constructor(private promise: Promise<T>) {}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Implements Promise interface.
|
|
70
|
+
*/
|
|
71
|
+
then<TResult1 = T, TResult2 = never>(
|
|
72
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
73
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
74
|
+
): ResponsePromise<TResult1 | TResult2> {
|
|
75
|
+
return new ResponsePromise(this.promise.then(onfulfilled, onrejected));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Implements Promise interface.
|
|
80
|
+
*/
|
|
81
|
+
catch<TResult = never>(
|
|
82
|
+
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
|
83
|
+
): ResponsePromise<T | TResult> {
|
|
84
|
+
return new ResponsePromise(this.promise.catch(onrejected));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Implements Promise interface.
|
|
89
|
+
*/
|
|
90
|
+
finally(onfinally?: (() => void) | null): ResponsePromise<T> {
|
|
91
|
+
return new ResponsePromise(this.promise.finally(onfinally));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns a promise that resolves to null if http status code
|
|
96
|
+
* or service error code matches one of the provided codes.
|
|
97
|
+
* If no codes are specified, all codes are ignored.
|
|
98
|
+
*/
|
|
99
|
+
ignore(...codes: number[]): ResponsePromise<T | null> {
|
|
100
|
+
return new ResponsePromise(ServiceError.ignore(codes, this.promise));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns a promise that resolves to either the response body
|
|
105
|
+
* or a ServiceError.
|
|
106
|
+
*/
|
|
107
|
+
combine(): Promise<EitherResponse<T>> {
|
|
108
|
+
return new ResponsePromise(ServiceError.combine<T>(this.promise));
|
|
109
|
+
}
|
|
46
110
|
}
|
|
47
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Either a response body or a service error.
|
|
114
|
+
*/
|
|
115
|
+
type EitherResponse<T> = { ok: true; body: T; err?: ServiceError } | { ok: false; body?: T, err: ServiceError; };
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* An error returned from an api service.
|
|
119
|
+
*/
|
|
48
120
|
export class ServiceError extends Error {
|
|
49
121
|
constructor(
|
|
50
122
|
public status: number, // http status
|
|
@@ -58,6 +130,10 @@ export class ServiceError extends Error {
|
|
|
58
130
|
Object.setPrototypeOf(this, ServiceError.prototype);
|
|
59
131
|
}
|
|
60
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Returns the http status code from err.
|
|
135
|
+
* If err isn't an instance of ServiceError, -1 is returned.
|
|
136
|
+
*/
|
|
61
137
|
static status(err: any): number {
|
|
62
138
|
if (err instanceof ServiceError) {
|
|
63
139
|
return err.status;
|
|
@@ -65,6 +141,10 @@ export class ServiceError extends Error {
|
|
|
65
141
|
return -1;
|
|
66
142
|
}
|
|
67
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Returns the service error code from err.
|
|
146
|
+
* If err isn't an instance of ServiceError, -1 is returned.
|
|
147
|
+
*/
|
|
68
148
|
static code(err: any): number {
|
|
69
149
|
if (err instanceof ServiceError) {
|
|
70
150
|
return err.code;
|
|
@@ -72,11 +152,19 @@ export class ServiceError extends Error {
|
|
|
72
152
|
return -1;
|
|
73
153
|
}
|
|
74
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Returns a promise that resolves to null if http status code
|
|
157
|
+
* or service error code matches one of the provided codes.
|
|
158
|
+
* If no codes are specified, all codes are ignored.
|
|
159
|
+
*/
|
|
75
160
|
static async ignore<T>(codes: number[], response: Promise<T>): Promise<T | null> {
|
|
76
161
|
try {
|
|
77
162
|
return await response;
|
|
78
163
|
} catch (err) {
|
|
79
164
|
if (err instanceof ServiceError) {
|
|
165
|
+
if (codes.length === 0) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
80
168
|
for (const code of codes) {
|
|
81
169
|
if (err.status === code || err.code === code) {
|
|
82
170
|
return null;
|
|
@@ -87,6 +175,24 @@ export class ServiceError extends Error {
|
|
|
87
175
|
}
|
|
88
176
|
}
|
|
89
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Returns a promise that resolves to either T or a ServiceError.
|
|
180
|
+
*/
|
|
181
|
+
static async combine<T>(response: Promise<T>): Promise<EitherResponse<T>> {
|
|
182
|
+
try {
|
|
183
|
+
const body = await response;
|
|
184
|
+
return { ok: true, body };
|
|
185
|
+
} catch (err) {
|
|
186
|
+
if (err instanceof ServiceError) {
|
|
187
|
+
return { ok: false, err }
|
|
188
|
+
}
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Constructs a ServiceError from the provided response data.
|
|
195
|
+
*/
|
|
90
196
|
static from_res(res: ResponseData): ServiceError {
|
|
91
197
|
let message = res.body;
|
|
92
198
|
let code = res.status;
|
|
@@ -101,10 +207,14 @@ export class ServiceError extends Error {
|
|
|
101
207
|
}
|
|
102
208
|
}
|
|
103
209
|
|
|
210
|
+
/**
|
|
211
|
+
* BaseServiceClient contains the logic for executing http requests.
|
|
212
|
+
* This class is meant to be extended by the generated code.
|
|
213
|
+
*/
|
|
104
214
|
export abstract class BaseServiceClient {
|
|
105
|
-
private options:
|
|
215
|
+
private options: RequestOptions;
|
|
106
216
|
|
|
107
|
-
constructor(options?:
|
|
217
|
+
constructor(options?: RequestOptions) {
|
|
108
218
|
this.options = options ?? {};
|
|
109
219
|
}
|
|
110
220
|
|
|
@@ -131,6 +241,10 @@ export abstract class BaseServiceClient {
|
|
|
131
241
|
return url;
|
|
132
242
|
}
|
|
133
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Perform the http request or pass it to the intercept function
|
|
246
|
+
* if one was configured.
|
|
247
|
+
*/
|
|
134
248
|
private async fetch(req: RequestData, options?: RequestOptions): Promise<ResponseData> {
|
|
135
249
|
if (options?.intercept) {
|
|
136
250
|
return options.intercept(req, this.fetch.bind(this));
|
|
@@ -147,28 +261,47 @@ export abstract class BaseServiceClient {
|
|
|
147
261
|
};
|
|
148
262
|
}
|
|
149
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Returns true if the response status was a 4xx error.
|
|
266
|
+
*/
|
|
150
267
|
private is_4xx(res: ResponseData): boolean {
|
|
151
268
|
return 400 <= res.status && res.status < 500;
|
|
152
269
|
}
|
|
153
270
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Returns the merged options.
|
|
273
|
+
*/
|
|
274
|
+
private get_options(options: RequestOptions): RequestOptions {
|
|
157
275
|
return {
|
|
158
276
|
...this.options,
|
|
159
|
-
...service_options,
|
|
160
|
-
...method_options,
|
|
161
277
|
...options,
|
|
162
278
|
headers: {
|
|
163
279
|
...this.options.headers,
|
|
164
|
-
...method_options?.headers,
|
|
165
|
-
...service_options?.headers,
|
|
166
280
|
...options.headers,
|
|
167
281
|
}
|
|
168
282
|
};
|
|
169
283
|
}
|
|
170
284
|
|
|
171
|
-
|
|
285
|
+
/**
|
|
286
|
+
* A delegate to _request that wraps the response in a ResponsePromise.
|
|
287
|
+
*/
|
|
288
|
+
protected request(
|
|
289
|
+
service: string,
|
|
290
|
+
name: string,
|
|
291
|
+
method: string,
|
|
292
|
+
route: string,
|
|
293
|
+
body: any,
|
|
294
|
+
options: { query?: any } & RequestOptions = {}
|
|
295
|
+
): ResponsePromise<any> {
|
|
296
|
+
const promise = this._request(service, name, method, route, body, options);
|
|
297
|
+
return new ResponsePromise(promise);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* The main logic for fulfilling a request as perscribed by
|
|
302
|
+
* the request options.
|
|
303
|
+
*/
|
|
304
|
+
private async _request(
|
|
172
305
|
service: string,
|
|
173
306
|
name: string,
|
|
174
307
|
method: string,
|
|
@@ -176,7 +309,7 @@ export abstract class BaseServiceClient {
|
|
|
176
309
|
body: any,
|
|
177
310
|
options: { query?: any } & RequestOptions = {}
|
|
178
311
|
): Promise<any> {
|
|
179
|
-
options = this.get_options(
|
|
312
|
+
options = this.get_options(options);
|
|
180
313
|
const url = this.build_url(route, options, options.query ?? {});
|
|
181
314
|
const headers = Object.assign({
|
|
182
315
|
"User-Agent": "CDL/ServiceClient"
|