Files
SCM-Manager/scm-ui/ui-components/src/apiclient.ts

143 lines
3.9 KiB
TypeScript
Raw Normal View History

import { contextPath } from "./urls";
2019-10-21 10:57:56 +02:00
import { createBackendError, ForbiddenError, isBackendError, UnauthorizedError } from "./errors";
import { BackendErrorContent } from "./errors";
2019-11-18 11:45:48 +01:00
const extractXsrfTokenFromJwt = (jwt: string) => {
const parts = jwt.split(".");
if (parts.length === 3) {
return JSON.parse(atob(parts[1])).xsrf;
}
};
// @VisibleForTesting
export const extractXsrfTokenFromCookie = (cookieString?: string) => {
if (cookieString) {
const cookies = cookieString.split(";");
for (const c of cookies) {
const parts = c.trim().split("=");
if (parts[0] === "X-Bearer-Token") {
return extractXsrfTokenFromJwt(parts[1]);
}
}
}
};
const extractXsrfToken = () => {
return extractXsrfTokenFromCookie(document.cookie);
};
const applyFetchOptions: (p: RequestInit) => RequestInit = o => {
2019-11-18 11:45:48 +01:00
const headers: { [key: string]: string } = {
Cache: "no-cache",
2019-03-12 13:55:34 +01:00
// identify the request as ajax request
"X-Requested-With": "XMLHttpRequest",
2019-11-18 11:45:48 +01:00
// identify the web interface
"X-SCM-Client": "WUI"
};
2019-11-18 11:45:48 +01:00
const xsrf = extractXsrfToken();
if (xsrf) {
headers["X-XSRF-Token"] = xsrf;
}
o.credentials = "same-origin";
o.headers = headers;
return o;
};
2018-11-15 21:39:08 +01:00
function handleFailure(response: Response) {
if (!response.ok) {
2018-11-15 21:39:08 +01:00
if (isBackendError(response)) {
return response.json().then((content: BackendErrorContent) => {
throw createBackendError(content, response.status);
});
2018-11-15 21:39:08 +01:00
} else {
2019-02-25 17:40:53 +01:00
if (response.status === 401) {
throw new UnauthorizedError("Unauthorized", 401);
2019-03-04 11:49:12 +01:00
} else if (response.status === 403) {
throw new ForbiddenError("Forbidden", 403);
2019-02-25 17:40:53 +01:00
}
2019-03-04 11:49:12 +01:00
throw new Error("server returned status code " + response.status);
}
}
return response;
}
export function createUrl(url: string) {
if (url.includes("://")) {
return url;
}
let urlWithStartingSlash = url;
if (url.indexOf("/") !== 0) {
urlWithStartingSlash = "/" + urlWithStartingSlash;
2018-07-11 22:01:36 +02:00
}
2018-10-01 17:22:03 +02:00
return `${contextPath}/api/v2${urlWithStartingSlash}`;
}
class ApiClient {
get(url: string): Promise<Response> {
return fetch(createUrl(url), applyFetchOptions({})).then(handleFailure);
}
2019-11-05 16:10:41 +01:00
post(url: string, payload?: any, contentType = "application/json") {
return this.httpRequestWithJSONBody("POST", url, contentType, payload);
}
postBinary(url: string, fileAppender: (p: FormData) => void) {
2019-10-21 10:57:56 +02:00
const formData = new FormData();
2019-08-30 09:11:14 +02:00
fileAppender(formData);
2019-10-21 10:57:56 +02:00
const options: RequestInit = {
method: "POST",
body: formData
};
2019-08-30 09:11:14 +02:00
return this.httpRequestWithBinaryBody(options, url);
}
2019-10-21 10:57:56 +02:00
put(url: string, payload: any, contentType = "application/json") {
return this.httpRequestWithJSONBody("PUT", url, contentType, payload);
2018-07-11 17:02:38 +02:00
}
2018-10-25 13:45:52 +02:00
head(url: string) {
let options: RequestInit = {
method: "HEAD"
2018-10-25 13:45:52 +02:00
};
options = applyFetchOptions(options);
2018-11-15 21:39:08 +01:00
return fetch(createUrl(url), options).then(handleFailure);
2018-10-15 16:45:44 +02:00
}
delete(url: string): Promise<Response> {
let options: RequestInit = {
method: "DELETE"
};
options = applyFetchOptions(options);
2018-11-15 21:39:08 +01:00
return fetch(createUrl(url), options).then(handleFailure);
}
2019-11-05 16:10:41 +01:00
httpRequestWithJSONBody(method: string, url: string, contentType: string, payload?: any): Promise<Response> {
2019-10-21 10:57:56 +02:00
const options: RequestInit = {
2019-11-05 16:10:41 +01:00
method: method
};
2019-11-05 16:10:41 +01:00
if (payload) {
options.body = JSON.stringify(payload);
}
2019-08-30 09:11:14 +02:00
return this.httpRequestWithBinaryBody(options, url, contentType);
}
2019-10-21 10:57:56 +02:00
httpRequestWithBinaryBody(options: RequestInit, url: string, contentType?: string) {
options = applyFetchOptions(options);
2019-08-30 09:11:14 +02:00
if (contentType) {
if (!options.headers) {
options.headers = new Headers();
}
// @ts-ignore
options.headers["Content-Type"] = contentType;
2019-08-30 09:11:14 +02:00
}
2018-11-15 21:39:08 +01:00
return fetch(createUrl(url), options).then(handleFailure);
}
}
2019-10-21 10:57:56 +02:00
export const apiClient = new ApiClient();