aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd/src/http/common.ts
blob: 25c69012ae433d291823b98c8340a7ef284d15d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import axios, { Axios, AxiosError, AxiosResponse } from "axios";
import { BehaviorSubject, Observable } from "rxjs";
import { identity } from "lodash";

export { axios };

export const apiBaseUrl = "/api";

export class HttpNetworkError extends Error {
  constructor(public innerError?: AxiosError) {
    super();
  }
}

export class HttpForbiddenError extends Error {
  constructor(
    public type: "unauthorized" | "forbidden",
    public innerError?: AxiosError
  ) {
    super();
  }
}

export class HttpNotFoundError extends Error {
  constructor(public innerError?: AxiosError) {
    super();
  }
}

function convertNetworkError(error: AxiosError): never {
  if (error.isAxiosError && error.response == null) {
    throw new HttpNetworkError(error);
  } else {
    throw error;
  }
}

function convertForbiddenError(error: AxiosError): never {
  const statusCode = error.response?.status;
  if (statusCode === 401 || statusCode === 403) {
    throw new HttpForbiddenError(
      statusCode === 401 ? "unauthorized" : "forbidden",
      error
    );
  } else {
    throw error;
  }
}

function convertNotFoundError(error: AxiosError): never {
  const statusCode = error.response?.status;
  if (statusCode === 404) {
    throw new HttpNotFoundError(error);
  } else {
    throw error;
  }
}

export function configureAxios(axios: Axios): void {
  axios.interceptors.response.use(identity, convertNetworkError);
  axios.interceptors.response.use(identity, convertForbiddenError);
  axios.interceptors.response.use(identity, convertNotFoundError);
}

configureAxios(axios);

const tokenSubject = new BehaviorSubject<string | null>(null);

export function getHttpToken(): string | null {
  return tokenSubject.value;
}

export function setHttpToken(token: string | null): void {
  tokenSubject.next(token);

  if (token == null) {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    delete axios.defaults.headers.common["Authorization"];
  } else {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
  }
}

export const token$: Observable<string | null> = tokenSubject.asObservable();

export class NotModified {}

export interface BlobWithEtag {
  data: Blob;
  etag: string;
}

export function extractResponseData<T>(res: AxiosResponse<T>): T {
  return res.data;
}

export function convertToNotModified(error: AxiosError): NotModified {
  const statusCode = error.response?.status;
  if (statusCode == 304) {
    return new NotModified();
  } else {
    throw error;
  }
}

export function convertToBlobWithEtag(res: AxiosResponse<Blob>): BlobWithEtag {
  return {
    data: res.data,
    etag: (res.headers as Record<"etag", string>)["etag"],
  };
}

export function extractEtag(res: AxiosResponse): string {
  return (res.headers as Record<"etag", string>)["etag"];
}

export interface Page<T> {
  pageNumber: number;
  pageSize: number;
  totalPageCount: number;
  totalCount: number;
  items: T[];
}