# 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<ApiRestResponse>;
          }
        })
        .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<ApiRestResponse>;
			}
		  })
		  .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}}");
`

```
