-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathopenapi-request-builder.ts
95 lines (86 loc) · 3.47 KB
/
openapi-request-builder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { AxiosResponse } from 'axios';
import { Destination, DestinationNameAndJwt } from '../connectivity/scp-cf';
import { buildAxiosRequestConfig } from '../http-client';
import type {
ConstructorType,
FunctionReturnType,
ParametersType,
UnwrapAxiosResponse
} from './types';
/**
* @experimental This API is experimental and might change in newer versions. Use with caution.
* Generic request builder for building and executing requests based on apis generated by the OpenAPI generator.
* @typeparam ApiT Interface of the generated api. All properties of the interface will be treated as functions.
* @typeparam FnT Literal string type of the function name, must be a key of `ApiT` and represent a function.
*/
export class OpenApiRequestBuilder<ApiT, FnT extends keyof ApiT> {
private customHeaders: Record<string, string> = {};
private args: ParametersType<ApiT, FnT>;
/**
* Create an instance of `RestRequestBuilder`.
* @param apiConstructor Constructor of the underlying OpenApi api definition.
* @param fn Name of the function represented in thie request builder.
* @param args Arguments to pass to the api function.
*/
constructor(
private apiConstructor: ConstructorType<ApiT>,
public fn: FnT,
...args: ParametersType<ApiT, FnT>
) {
this.args = args;
}
/**
* Add custom headers to the request. If a header field with the given name already exists it is overwritten.
*
* @param headers Key-value pairs denoting additional custom headers
* @returns The request builder itself, to facilitate method chaining
*/
addCustomHeaders(headers: Record<string, string>): this {
Object.entries(headers).forEach(([key, value]) => {
this.customHeaders[key.toLowerCase()] = value;
});
return this;
}
/**
* Execute request and get a raw AxiosResponse, including all information about the HTTP response.
* This especially comes in handy, when you need to access the headers or status code of the response.
* @param destination Destination to execute the request against.
* @param options Options to employ when fetching destinations.
* @returns A promise resolving to an AxiosResponse.
*/
async executeRaw(
destination: Destination | DestinationNameAndJwt
): Promise<FunctionReturnType<ApiT, FnT>> {
const requestConfig = await buildAxiosRequestConfig(destination, {
headers: this.customHeaders
});
const api = new this.apiConstructor(requestConfig);
const fn = api[this.fn];
if (typeof fn === 'function') {
return fn.apply(api, this.args);
}
throw new Error(
`Could not execute request. '${this.fn}' is not a function of ${this.apiConstructor.name}.`
);
}
/**
* Execute request and get the response data. Use this to conveniently access the data of a service without technical information about the response.
* @param destination Destination to execute the request against.
* @param options Options to employ when fetching destinations.
* @returns A promise resolving to the requested return type.
*/
async execute(
destination: Destination | DestinationNameAndJwt
): Promise<UnwrapAxiosResponse<FunctionReturnType<ApiT, FnT>>> {
const response = await this.executeRaw(destination);
if (isAxiosResponse(response)) {
return response.data;
}
throw new Error(
'Could not access response data. Response was not an axios response.'
);
}
}
function isAxiosResponse(val: any): val is AxiosResponse {
return 'data' in val;
}