Current status of ccm-apiclient-commons. Trying to figure best way for zero dependencies and supporting browsers and node environments

Jens Pelzetter 2020-07-11 18:14:09 +02:00
parent 01444aa09e
commit cdde8ce67a
3 changed files with 161 additions and 1 deletions

View File

@ -61,6 +61,12 @@
"integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
"dev": true
},
"@types/node": {
"version": "12.12.50",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz",
"integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.6.0.tgz",

View File

@ -17,6 +17,7 @@
},
"dependencies": {},
"devDependencies": {
"@types/node": "^12.12.50",
"@typescript-eslint/eslint-plugin": "^3.6.0",
"@typescript-eslint/parser": "^3.6.0",
"eslint": "^7.4.0",

View File

@ -1,2 +1,155 @@
import http from "http";
import { AnyARecord } from "dns";
export * from "./entities";
export * from "./RequestInitProvider";
export * from "./RequestInitProvider";
export interface LibreCcmApiClient {
get(
endpoint: string,
searchParams: Record<string, string>
): Promise<ApiResponse>;
post(
endpoint: string,
searchParams: Record<string, string>,
body: unknown
): Promise<Response>;
put(endpoint: string, body: Record<string, unknown>): Promise<Response>;
delete(endpoint: string): Promise<Response>;
head(endpoint: string): Promise<Response>;
options(endpoint: string): Promise<Response>;
}
export interface ApiResponse {
status: number;
statusText: string;
json(): Promise<Record<string, unknown>>;
blob(): Promise<Blob>;
text(): Promise<string>
}
export interface ApiError {
status: number;
statusText: string;
method: "get" | "post" | "put" | "delete" | "head" | "option";
message: string;
url: string;
}
export function buildUrl(base: string, endpoint: string, searchParams?: Record<string, string>): string {
const url = new URL(base);
url.pathname = endpoint;
if (searchParams) {
const urlSearchParams: URLSearchParams = new URLSearchParams();
for (const key in searchParams) {
urlSearchParams.append(key, searchParams[key]);
}
url.search = urlSearchParams.toString();
}
return url.href;
}
export function buildEmbeddedApiClient(): LibreCcmApiClient {
if (!document) {
throw "document global variable is not available. Please use the buildRemoteApiClient.";
}
const baseUrl = new URL(document.documentURI);
baseUrl.hash = "";
baseUrl.password = "";
baseUrl.pathname = "";
baseUrl.search = "";
baseUrl.username = "";
return new EmbeddedApiClient(baseUrl.href, {
credentials: "include",
mode: "same-origin",
});
}
class FetchResponse implements ApiResponse {
readonly status: number;
readonly statusText: string;
#response: Response;
constructor(response: Response) {
this.status = response.status;
this.statusText = response.statusText;
this.#response = response;
}
json(): Promise<Record<string, unknown>> {
return this.#response.json();
}
blob(): Promise<Blob> {
return this.#response.blob();
}
text(): Promise<string> {
return this.#response.text();
}
}
class EmbeddedApiClient implements LibreCcmApiClient {
#baseUrl: string;
#fetchOptions: RequestInit;
constructor(baseUrl: string, fetchOptions: RequestInit) {
this.#baseUrl = baseUrl;
this.#fetchOptions = fetchOptions;
}
async get(
endpoint: string,
searchParams?: Record<string, string>
): Promise<ApiResponse> {
const fetchOptions: RequestInit = {};
Object.assign(fetchOptions, this.#fetchOptions);
fetchOptions.method = "get";
const url = buildUrl(this.#baseUrl, endpoint, searchParams);
try {
const response = await fetch(url, this.#fetchOptions);
if (response.ok) {
return new FetchResponse(response);
} else {
throw {
status: response.status,
statusText: response.statusText,
method: "get",
message: "Received an error from the API endpoint. ",
url
}
}
} catch(err) {
throw `Failed to execute GET on ${url}: ${err}`;
}
}
async post(
endpoint: string,
searchParams: Record<string, string>,
body: unknown
): Promise<Response> {
throw "Not implemented yet";
}
put(endpoint: string, body: Record<string, unknown>): Promise<Response> {
throw "Not implemented yet";
}
delete(endpoint: string): Promise<Response> {
throw "Not implemented yet";
}
head(endpoint: string): Promise<Response> {
throw "Not implemented yet";
}
options(endpoint: string): Promise<Response> {
throw "Not implemented yet";
}
}