2018-06-15 08:13:33 +02:00
|
|
|
import { HTTPCache } from './HTTPCache';
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
export type Params =
|
|
|
|
| URLSearchParams
|
|
|
|
| string
|
|
|
|
| { [key: string]: string | string[] | undefined }
|
|
|
|
| Iterable<[string, string]>
|
|
|
|
| Array<[string, string]>;
|
2018-06-15 08:13:33 +02:00
|
|
|
|
|
|
|
export abstract class RESTDataSource<TContext = any> {
|
|
|
|
abstract baseURL: string;
|
|
|
|
|
|
|
|
httpCache!: HTTPCache;
|
|
|
|
context!: TContext;
|
|
|
|
|
|
|
|
public willSendRequest?(request: Request): void;
|
|
|
|
|
|
|
|
public willReceiveCache(httpCache: HTTPCache) {
|
|
|
|
this.httpCache = httpCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
public willReceiveContext(context: TContext) {
|
|
|
|
this.context = context;
|
|
|
|
}
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
protected async get<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
options?: RequestInit,
|
2018-06-19 09:40:42 +02:00
|
|
|
): Promise<TResponse> {
|
|
|
|
return this.fetch<TResponse>(
|
|
|
|
path,
|
|
|
|
params,
|
|
|
|
Object.assign({ method: 'GET' }, options),
|
|
|
|
);
|
2018-06-15 08:13:33 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
protected async post<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
options?: RequestInit,
|
2018-06-19 09:40:42 +02:00
|
|
|
): Promise<TResponse> {
|
|
|
|
return this.fetch<TResponse>(
|
|
|
|
path,
|
|
|
|
params,
|
|
|
|
Object.assign({ method: 'POST' }, options),
|
|
|
|
);
|
2018-06-15 08:13:33 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
protected async patch<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
options?: RequestInit,
|
2018-06-19 09:40:42 +02:00
|
|
|
): Promise<TResponse> {
|
|
|
|
return this.fetch<TResponse>(
|
|
|
|
path,
|
|
|
|
params,
|
|
|
|
Object.assign({ method: 'PATCH' }, options),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected async put<TResponse>(
|
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
options?: RequestInit,
|
|
|
|
): Promise<TResponse> {
|
|
|
|
return this.fetch<TResponse>(
|
|
|
|
path,
|
|
|
|
params,
|
|
|
|
Object.assign({ method: 'PUT' }, options),
|
|
|
|
);
|
2018-06-15 08:13:33 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
protected async delete<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
options?: RequestInit,
|
2018-06-19 09:40:42 +02:00
|
|
|
): Promise<TResponse> {
|
|
|
|
return this.fetch<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path,
|
|
|
|
params,
|
|
|
|
Object.assign({ method: 'DELETE' }, options),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-06-19 09:40:42 +02:00
|
|
|
private async fetch<TResponse>(
|
2018-06-15 08:13:33 +02:00
|
|
|
path: string,
|
|
|
|
params?: Params,
|
|
|
|
init?: RequestInit,
|
2018-06-19 09:40:42 +02:00
|
|
|
): Promise<TResponse> {
|
2018-06-15 08:13:33 +02:00
|
|
|
const url = new URL(path, this.baseURL);
|
|
|
|
|
|
|
|
if (params && Object.keys(params).length > 0) {
|
|
|
|
// Append params to existing params in the path
|
|
|
|
for (const [name, value] of new URLSearchParams(params)) {
|
|
|
|
url.searchParams.append(name, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.trace(`${(init && init.method) || 'GET'} ${url}`, async () => {
|
|
|
|
const request = new Request(String(url));
|
|
|
|
if (this.willSendRequest) {
|
|
|
|
this.willSendRequest(request);
|
|
|
|
}
|
|
|
|
const response = await this.httpCache.fetch(request, init);
|
|
|
|
if (response.ok) {
|
|
|
|
return response.json();
|
|
|
|
} else {
|
|
|
|
throw new Error(
|
|
|
|
`${response.status} ${response.statusText}: ${await response.text()}`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private async trace<Result>(
|
|
|
|
label: string,
|
|
|
|
fn: () => Promise<Result>,
|
|
|
|
): Promise<Result> {
|
|
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
|
|
return await fn();
|
|
|
|
} finally {
|
|
|
|
const duration = Date.now() - startTime;
|
|
|
|
//to remove the unused error
|
|
|
|
label;
|
|
|
|
duration;
|
|
|
|
// console.log(`${label} (${duration}ms)`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|