-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathauthApiServer.ts
117 lines (97 loc) · 3.66 KB
/
authApiServer.ts
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
import { revalidatePath, revalidateTag } from "next/cache";
import { headers } from "next/headers";
import { SERVER_AUTH_ERROR } from "@/shared/constants/auth";
import { getSearchParams } from "@/shared/lib";
import { getServerAccessToken, getServerRefreshToken, getServerTokens } from "@/shared/models/auth";
import { BaseServerApi } from "../baseServerApi";
import type { GetOptions, MutateOptions } from "../api.interface";
import type { TokenDTO } from "./auth.interface";
class AuthApiServer extends BaseServerApi {
private static instance: AuthApiServer;
private constructor() {
super(process.env.NEXT_PUBLIC_API_URL!);
}
static getInstance() {
if (!AuthApiServer.instance) {
AuthApiServer.instance = new AuthApiServer();
}
return AuthApiServer.instance;
}
async get<T>(url: string, options?: GetOptions): Promise<T> {
const params = getSearchParams(options?.params, true);
const accessToken = options?._tokens?.accessToken || (await getServerAccessToken());
const refreshToken = options?._tokens?.accessToken || (await getServerRefreshToken());
if (!accessToken || !refreshToken) return SERVER_AUTH_ERROR as T;
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${url}${params}`, {
next: {
revalidate: this.getNextRevalidate(options),
tags: options?.tags,
},
cache: options?.cache,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
...options?.headers,
},
});
if (!response.ok) throw new Error();
const data = (await response.json()) as T;
return data;
} catch {
return await this.refreshTokens({ accessToken, refreshToken }, async (tokens) => {
return await this.get<T>(url, {
...(options as GetOptions),
_tokens: tokens,
});
});
}
}
async mutate<T>(method: string, url: string, options?: MutateOptions): Promise<T> {
const params = getSearchParams(options?.params, true);
const { accessToken, refreshToken } = await getServerTokens();
if (!accessToken || !refreshToken) return SERVER_AUTH_ERROR as T;
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${url}${params}`, {
method,
body: JSON.stringify(options?.body),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
...options?.headers,
},
});
if (!response.ok) throw new Error();
options?.revalidateTags?.forEach((tag) => revalidateTag(tag));
options?.revalidatePath?.forEach((path) => revalidatePath(path.path, path.type));
const data = (await response.json()) as T;
return data;
} catch {
return await this.refreshTokens({ accessToken, refreshToken }, async ({ accessToken, refreshToken }) => {
return await this.mutate<T>(method, url, {
...options,
_tokens: { accessToken, refreshToken },
});
});
}
}
private async refreshTokens<T>(
tokens: Partial<TokenDTO>,
callback: (tokens: TokenDTO) => T | Promise<T>,
): Promise<T> {
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_API_URL}/api/auth/refresh`, {
method: "POST",
body: JSON.stringify(tokens),
headers: await headers(),
});
if (!response.ok) throw new Error();
const newTokens = (await response.json()) as TokenDTO;
const result = await callback(newTokens);
return result;
} catch {
return SERVER_AUTH_ERROR as T;
}
}
}
export const authApiServer = AuthApiServer.getInstance();