# ts-rpc #### typescript fetch template --- ```typescript // // {{.CreatedOn.Format "Jan 02, 2006 15:04:05 UTC" }} // export interface ApiRestResponse { data?: unknown; error: string | null; } class Api { apiUrl: string; localStorage: Storage | null; constructor(apiurl: string) { this.apiUrl = apiurl; this.localStorage = null; } request(method: string, url: string, data: unknown, timeout = 7000, upload = false) { return new Promise((resolve, reject) => { let auth: string; const headers: { [key: string]: string } = { "Content-Type": upload ? "multipart/form-data" : "application/json", "Cache-Control": "no-cache", }; if (this.localStorage) { auth = localStorage.getItem("jwt-token") as string; headers["Auth-Token"] = auth; } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); let requestOptions: RequestInit = { method: method, body: data ? JSON.stringify(data) : undefined, cache: "no-store", mode: "cors", credentials: "include", headers: headers || {}, signal: controller.signal, }; if (upload) { requestOptions = { method: method, body: data as FormData, signal: controller.signal, }; } fetch(url, requestOptions) .then((response) => { if (!response.ok) { const error = `api.error.${response.statusText}`; throw error; } else { if (this.localStorage) { const jwt = response.headers.get("Auth-Token"); if (jwt) { this.localStorage.setItem("jwt-token", jwt); } } return response.json() as Promise; } }) .then((data) => { clearTimeout(timeoutId); if (typeof data === "object" && data.hasOwnProperty("data") && data.hasOwnProperty("error")) { const d: ApiRestResponse = data; if (d.error) { throw d.error; } else { resolve(d); } } else { throw "api.error.wrongdatatype"; } }) .catch((error) => { clearTimeout(timeoutId); if ((error as Error).toString() === "DOMException: The user aborted a request.") { reject(new Error("api.error.timeouterror")); return; } if ((error as Error).toString() === "TypeError: Failed to fetch") { reject(new Error("api.error.connectionerror")); return; } reject(error); }); }); } processResult(url: string, result: ApiRestResponse): { data: unknown; error: string | null } { if (typeof result.data !== "object") { return { data: result.data, error: null }; } else if (!result.data) { result.data = {}; } return { data: result.data, error: null }; } processError( error: Error, url: string ): { data: unknown; error: string | null; } { if (error.message === "api.error.timeouterror") { Object.defineProperty(error, "__api_error__", { value: error.message, writable: false, }); return { data: null, error: error.message }; } if (error.message === "api.error.connectionerror") { Object.defineProperty(error, "__api_error__", { value: error.message, writable: false, }); return { data: null, error: error.message }; } return { data: null, error: error.message, }; } async POST( url: string, data: unknown, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { let upload = false; if (url.includes("/upload/")) { upload = true; } const result = (await this.request("POST", `${this.apiUrl}${url}`, data, timeout, upload)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>(async (resolve) => { let result = this.processError(error, `POST => ${this.apiUrl}${url}`); resolve(result); }); } } async GET( url: string, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { const result = (await this.request("GET", `${this.apiUrl}${url}`, null, timeout)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>(async (resolve) => { let result = this.processError(error, `GET => ${this.apiUrl}${url}`); resolve(result); }); } } async UPLOAD( url: string, data: unknown, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { const result = (await this.request("POST", `${this.apiUrl}${url}`, data, timeout, true)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>((resolve) => { resolve(this.processError(error, `POST => ${this.apiUrl}${url}`)); }); } } } const api = new Api("{{ .Url}}"); ``` --- #### Golang template as constant _note_: incuded in source code _note_: replce \` (backtick) inside \` (backtick) with \` + "\`" + \` ```golang package tsrpc const TsApiTemplate = ` // // {{.CreatedOn.Format "Jan 02, 2006 15:04:05 UTC" }} // export interface ApiRestResponse { data?: unknown; error: string | null; } class Api { apiUrl: string; localStorage: Storage | null; constructor(apiurl: string) { this.apiUrl = apiurl; this.localStorage = null; } request(method: string, url: string, data: unknown, timeout = 7000, upload = false) { return new Promise((resolve, reject) => { let auth: string; const headers: { [key: string]: string } = { "Content-Type": upload ? "multipart/form-data" : "application/json", "Cache-Control": "no-cache", }; if (this.localStorage) { auth = localStorage.getItem("jwt-token") as string; headers["Auth-Token"] = auth; } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); let requestOptions: RequestInit = { method: method, body: data ? JSON.stringify(data) : undefined, cache: "no-store", mode: "cors", credentials: "include", headers: headers || {}, signal: controller.signal, }; if (upload) { requestOptions = { method: method, body: data as FormData, signal: controller.signal, }; } fetch(url, requestOptions) .then((response) => { if (!response.ok) { const error = ` + "`" + `api.error.${response.statusText}` + "`" + `; throw error; } else { if (this.localStorage) { const jwt = response.headers.get("Auth-Token"); if (jwt) { this.localStorage.setItem("jwt-token", jwt); } } return response.json() as Promise; } }) .then((data) => { clearTimeout(timeoutId); if (typeof data === "object" && data.hasOwnProperty("data") && data.hasOwnProperty("error")) { const d: ApiRestResponse = data; if (d.error) { throw d.error; } else { resolve(d); } } else { throw "api.error.wrongdatatype"; } }) .catch((error) => { clearTimeout(timeoutId); if ((error as Error).toString() === "DOMException: The user aborted a request.") { reject(new Error("api.error.timeouterror")); return; } if ((error as Error).toString() === "TypeError: Failed to fetch") { reject(new Error("api.error.connectionerror")); return; } reject(error); }); }); } processResult(url: string, result: ApiRestResponse): { data: unknown; error: string | null } { if (typeof result.data !== "object") { return { data: result.data, error: null }; } else if (!result.data) { result.data = {}; } return { data: result.data, error: null }; } processError( error: Error, url: string ): { data: unknown; error: string | null; } { if (error.message === "api.error.timeouterror") { Object.defineProperty(error, "__api_error__", { value: error.message, writable: false, }); return { data: null, error: error.message }; } if (error.message === "api.error.connectionerror") { Object.defineProperty(error, "__api_error__", { value: error.message, writable: false, }); return { data: null, error: error.message }; } return { data: null, error: error.message, }; } async POST( url: string, data: unknown, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { let upload = false; if (url.includes("/upload/")) { upload = true; } const result = (await this.request("POST", ` + "`" + `${this.apiUrl}${url}` + "`" + `, data, timeout, upload)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>(async (resolve) => { let result = this.processError(error, ` + "`" + `POST => ${this.apiUrl}${url}` + "`" + `); resolve(result); }); } } async GET( url: string, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { const result = (await this.request("GET", ` + "`" + `${this.apiUrl}${url}` + "`" + `, null, timeout)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>(async (resolve) => { let result = this.processError(error, ` + "`" + `GET => ${this.apiUrl}${url}` + "`" + `); resolve(result); }); } } async UPLOAD( url: string, data: unknown, timeout?: number ): Promise<{ data: unknown; error: string | null; }> { try { const result = (await this.request("POST", ` + "`" + `${this.apiUrl}${url}` + "`" + `, data, timeout, true)) as ApiRestResponse; return this.processResult(url, result); } catch (error) { return new Promise<{ data: unknown; error: string | null; }>((resolve) => { resolve(this.processError(error, ` + "`" + `POST => ${this.apiUrl}${url}` + "`" + `)); }); } } } const api = new Api("{{ .Url}}"); ` ```