@tatil/server-api 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +4 -0
- package/package.json +14 -0
- package/src/utils/auth.js +27 -0
- package/src/utils/reklog.js +11 -0
- package/src/utils/tatilsepeti.js +172 -0
- package/src/utils/tokenManager.js +41 -0
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tatil/server-api",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Tatilsepeti Server Api for Next.js server-side operations",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"axios": "^1.13.2",
|
|
11
|
+
"moment": "^2.29.4",
|
|
12
|
+
"reklog-request": "^0.0.22"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RequestLogger } from './reklog';
|
|
2
|
+
|
|
3
|
+
const { API_URL, API_USERNAME, API_PASSWORD } = process.env;
|
|
4
|
+
|
|
5
|
+
const logger = RequestLogger();
|
|
6
|
+
|
|
7
|
+
export const getNewToken = async () => {
|
|
8
|
+
const options = {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
body: `grant_type=password&username=${API_USERNAME}&password=${API_PASSWORD}`,
|
|
11
|
+
headers: {
|
|
12
|
+
Accept: 'application/json',
|
|
13
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const body = {
|
|
18
|
+
grant_type: 'password',
|
|
19
|
+
username: API_USERNAME,
|
|
20
|
+
password: API_PASSWORD,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const req = await fetch(`${API_URL}/token`, options);
|
|
24
|
+
const { access_token, expires_in } = await req.json();
|
|
25
|
+
|
|
26
|
+
return { access_token, expires_in };
|
|
27
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ReklogRequest from 'reklog-request';
|
|
2
|
+
|
|
3
|
+
const { NODE_ENV, REKLOG_KEY } = process.env;
|
|
4
|
+
|
|
5
|
+
export const RequestLogger = () => {
|
|
6
|
+
return ReklogRequest.init(REKLOG_KEY, {
|
|
7
|
+
environment: NODE_ENV,
|
|
8
|
+
debug: false,
|
|
9
|
+
excludeEndpoints: ['/content/headermenuv2'],
|
|
10
|
+
});
|
|
11
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { cookies } from 'next/headers';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
import TokenManager from './tokenManager';
|
|
5
|
+
import { RequestLogger } from './reklog';
|
|
6
|
+
|
|
7
|
+
const { API_URL } = process.env;
|
|
8
|
+
|
|
9
|
+
class TatilsepetiApi {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.baseURL = API_URL;
|
|
12
|
+
this.instance = axios.create({
|
|
13
|
+
baseURL: API_URL,
|
|
14
|
+
});
|
|
15
|
+
this.logger = RequestLogger();
|
|
16
|
+
this.defaultHeaders = {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
joinEndpoint(endpoint) {
|
|
22
|
+
return endpoint.join('/');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fullEndpoint(endpoint) {
|
|
26
|
+
return `${this.baseURL}/api/v1/${this.joinEndpoint(endpoint)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
buildUrl(endpoint) {
|
|
30
|
+
if (Array.isArray(endpoint)) {
|
|
31
|
+
return this.fullEndpoint(endpoint);
|
|
32
|
+
}
|
|
33
|
+
return `${this.baseURL}/api/v1${endpoint}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getEndpointPath(endpoint) {
|
|
37
|
+
return Array.isArray(endpoint) ? this.joinEndpoint(endpoint) : endpoint;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setAuthCookies(accessToken, expiresAt) {
|
|
41
|
+
const response = new Response();
|
|
42
|
+
response.cookies.set('token', accessToken);
|
|
43
|
+
response.cookies.set('token_expire', expiresAt);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async getAuthHeaders() {
|
|
47
|
+
const cookieStore = await cookies();
|
|
48
|
+
const token = cookieStore.get('token');
|
|
49
|
+
const tokenExpire = cookieStore.get('token_expire');
|
|
50
|
+
|
|
51
|
+
const { token: newToken, tokenExpire: newExpire, refreshed } = await TokenManager.refreshTokenIfNeeded(
|
|
52
|
+
token?.value,
|
|
53
|
+
tokenExpire?.value
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (refreshed) {
|
|
57
|
+
this.setAuthCookies(newToken, newExpire);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
...this.defaultHeaders,
|
|
62
|
+
Authorization: `Bearer ${newToken}`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
createResponse(data, status = 200) {
|
|
67
|
+
return new Response(
|
|
68
|
+
JSON.stringify({
|
|
69
|
+
status: 'success',
|
|
70
|
+
data,
|
|
71
|
+
}),
|
|
72
|
+
{
|
|
73
|
+
status,
|
|
74
|
+
headers: { ...this.defaultHeaders },
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
createErrorResponse(message, status = 500) {
|
|
80
|
+
return new Response(
|
|
81
|
+
JSON.stringify({
|
|
82
|
+
status: 'error',
|
|
83
|
+
message,
|
|
84
|
+
}),
|
|
85
|
+
{
|
|
86
|
+
status,
|
|
87
|
+
headers: { ...this.defaultHeaders },
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async get(endpoint, params = {}) {
|
|
93
|
+
const endpointPath = this.getEndpointPath(endpoint);
|
|
94
|
+
const logId = this.logger.start(endpointPath, 'GET');
|
|
95
|
+
const url = this.buildUrl(endpoint);
|
|
96
|
+
|
|
97
|
+
const response = await this.instance.get(url, {
|
|
98
|
+
params,
|
|
99
|
+
headers: await this.getAuthHeaders(),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (!response) {
|
|
103
|
+
this.logger.end(logId, {
|
|
104
|
+
statusCode: 500,
|
|
105
|
+
response: 'No response from server',
|
|
106
|
+
params,
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!response.data) {
|
|
112
|
+
this.logger.end(logId, {
|
|
113
|
+
statusCode: response.status || 500,
|
|
114
|
+
response: 'No data in response',
|
|
115
|
+
params,
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const { data } = response;
|
|
121
|
+
|
|
122
|
+
this.logger.end(logId, {
|
|
123
|
+
statusCode: response.status,
|
|
124
|
+
response: data,
|
|
125
|
+
params,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async post(endpoint, body = {}) {
|
|
132
|
+
const endpointPath = this.getEndpointPath(endpoint);
|
|
133
|
+
const logId = this.logger.start(endpointPath, 'POST');
|
|
134
|
+
const url = this.buildUrl(endpoint);
|
|
135
|
+
|
|
136
|
+
const response = await this.instance.post(url, body, {
|
|
137
|
+
headers: await this.getAuthHeaders(),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!response) {
|
|
141
|
+
this.logger.end(logId, {
|
|
142
|
+
statusCode: 500,
|
|
143
|
+
response: 'No response from server',
|
|
144
|
+
body,
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!response.data) {
|
|
150
|
+
this.logger.end(logId, {
|
|
151
|
+
statusCode: response.status || 500,
|
|
152
|
+
response: 'No data in response',
|
|
153
|
+
body,
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const { data } = response;
|
|
159
|
+
|
|
160
|
+
this.logger.end(logId, {
|
|
161
|
+
statusCode: response.status,
|
|
162
|
+
response: data,
|
|
163
|
+
body,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return data;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const Tatilsepeti = new TatilsepetiApi();
|
|
171
|
+
|
|
172
|
+
export default Tatilsepeti;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
|
|
3
|
+
import { getNewToken } from './auth';
|
|
4
|
+
|
|
5
|
+
class TokenManager {
|
|
6
|
+
isTokenExpired(token, tokenExpire) {
|
|
7
|
+
if (!token || !tokenExpire) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const currentTime = moment().valueOf();
|
|
12
|
+
return currentTime >= Number(tokenExpire);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getExpirationTimestamp(expiresIn) {
|
|
16
|
+
return moment().add(Number(expiresIn), 'seconds').valueOf();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async refreshTokenIfNeeded(token, tokenExpire) {
|
|
20
|
+
if (!this.isTokenExpired(token, tokenExpire)) {
|
|
21
|
+
return {
|
|
22
|
+
token,
|
|
23
|
+
tokenExpire,
|
|
24
|
+
refreshed: false,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { access_token: accessToken, expires_in: expiresIn } = await getNewToken();
|
|
29
|
+
const expiresAt = this.getExpirationTimestamp(expiresIn);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
token: accessToken,
|
|
33
|
+
tokenExpire: expiresAt,
|
|
34
|
+
refreshed: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const TokenManagerInstance = new TokenManager();
|
|
40
|
+
|
|
41
|
+
export default TokenManagerInstance;
|