Skip to content

Commit 6064155

Browse files
committed
chore: BackendAdminAPI 추가를 위한 준비 작업
1 parent 9a9177a commit 6064155

File tree

6 files changed

+112
-81
lines changed

6 files changed

+112
-81
lines changed

packages/common/src/apis/client.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
22
import * as R from "remeda";
33

4-
import CommonSchemas from "../schemas";
4+
import BackendAPISchemas from '../schemas/backendAPI';
5+
import { getCookie } from '../utils/cookie';
56

67
const DEFAULT_ERROR_MESSAGE = "알 수 없는 문제가 발생했습니다, 잠시 후 다시 시도해주세요.";
78
const DEFAULT_ERROR_RESPONSE = {
@@ -12,20 +13,20 @@ const DEFAULT_ERROR_RESPONSE = {
1213
export class BackendAPIClientError extends Error {
1314
readonly name = "BackendAPIClientError";
1415
readonly status: number;
15-
readonly detail: CommonSchemas.ErrorResponseSchema;
16+
readonly detail: BackendAPISchemas.ErrorResponseSchema;
1617
readonly originalError: unknown;
1718

1819
constructor(error?: unknown) {
1920
let message: string = DEFAULT_ERROR_MESSAGE;
20-
let detail: CommonSchemas.ErrorResponseSchema = DEFAULT_ERROR_RESPONSE;
21+
let detail: BackendAPISchemas.ErrorResponseSchema = DEFAULT_ERROR_RESPONSE;
2122
let status = -1;
2223

2324
if (axios.isAxiosError(error)) {
2425
const response = error.response;
2526

2627
if (response) {
2728
status = response.status;
28-
detail = CommonSchemas.isObjectErrorResponseSchema(response.data)
29+
detail = BackendAPISchemas.isObjectErrorResponseSchema(response.data)
2930
? response.data
3031
: {
3132
type: "axios_error",
@@ -39,6 +40,7 @@ export class BackendAPIClientError extends Error {
3940
},
4041
],
4142
};
43+
message = detail.errors[0].detail || DEFAULT_ERROR_MESSAGE;
4244
}
4345
} else if (error instanceof Error) {
4446
message = error.message;
@@ -71,12 +73,33 @@ type AxiosRequestWithPayload = <T = any, R = AxiosResponse<T>, D = any>(
7173

7274
export class BackendAPIClient {
7375
readonly baseURL: string;
76+
protected readonly csrfCookieName: string;
7477
private readonly backendAPI: AxiosInstance;
7578

76-
constructor(baseURL: string, timeout: number) {
79+
constructor(
80+
baseURL: string,
81+
timeout: number,
82+
csrfCookieName: string = "csrftoken",
83+
withCredentials: boolean = false,
84+
) {
7785
const headers = { "Content-Type": "application/json" };
7886
this.baseURL = baseURL;
79-
this.backendAPI = axios.create({ baseURL, timeout, headers });
87+
this.csrfCookieName = csrfCookieName;
88+
this.backendAPI = axios.create({ baseURL, timeout, headers, withCredentials});
89+
90+
if (withCredentials) {
91+
this.backendAPI.interceptors.request.use(
92+
(config) => {
93+
config.headers["x-csrftoken"] = this.getCSRFToken();
94+
return config;
95+
},
96+
(error) => Promise.reject(error)
97+
);
98+
}
99+
}
100+
101+
getCSRFToken(): string | undefined {
102+
return getCookie(this.csrfCookieName);
80103
}
81104

82105
_safe_request_without_payload(

packages/common/src/apis/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import CommonSchemas from "../schemas";
1+
import BackendAPISchemas from "../schemas/backendAPI";
22
import { BackendAPIClient } from "./client";
33

44
namespace BackendAPIs {
5-
export const listSiteMaps = (client: BackendAPIClient) => () => client.get<CommonSchemas.FlattenedSiteMapSchema[]>("v1/cms/sitemap/");
6-
export const retrievePage = (client: BackendAPIClient) => (id: string) => client.get<CommonSchemas.PageSchema>(`v1/cms/page/${id}/`);
5+
export const listSiteMaps = (client: BackendAPIClient) => () => client.get<BackendAPISchemas.FlattenedSiteMapSchema[]>("v1/cms/sitemap/");
6+
export const retrievePage = (client: BackendAPIClient) => (id: string) => client.get<BackendAPISchemas.PageSchema>(`v1/cms/page/${id}/`);
77
}
88

99
export default BackendAPIs;

packages/common/src/components/dynamic_route.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import { AxiosError, AxiosResponse } from 'axios';
12
import * as React from "react";
23
import { useLocation, useParams } from 'react-router-dom';
34
import * as R from "remeda";
45

56
import { CircularProgress } from '@mui/material';
67
import { ErrorBoundary, Suspense } from '@suspensive/react';
78

8-
import { AxiosError, AxiosResponse } from 'axios';
99
import { BackendAPIClientError } from '../apis/client';
1010
import Hooks from "../hooks";
11-
import Schemas from "../schemas";
11+
import BackendAPISchemas from '../schemas/backendAPI';
1212
import Utils from '../utils';
1313
import { ErrorFallback } from './error_handler';
1414
import { MDXRenderer } from './mdx';
@@ -29,7 +29,7 @@ const LoginRequired: React.FC = () => <>401 Login Required</>;
2929
const PermissionDenied: React.FC = () => <>403 Permission Denied</>;
3030
const PageNotFound: React.FC = () => <>404 Not Found</>;
3131

32-
const throwPageNotFound = (message: string) => {
32+
const throwPageNotFound: (message: string) => never = (message) => {
3333
const errorStr = `RouteRenderer: ${message}`;
3434
const axiosError = new AxiosError(errorStr, errorStr, undefined, undefined, { status: 404 } as AxiosResponse);
3535
throw new BackendAPIClientError(axiosError);
@@ -80,7 +80,7 @@ export const RouteRenderer: React.FC = ErrorBoundary.with(
8080
const nestedSiteMap = Utils.buildNestedSiteMap(data);
8181

8282
const currentRouteCodes = ['', ...location.pathname.split('/').filter((code) => !R.isEmpty(code))];
83-
let currentSitemap: Schemas.NestedSiteMapSchema | undefined = nestedSiteMap[currentRouteCodes[0]];
83+
let currentSitemap: BackendAPISchemas.NestedSiteMapSchema | undefined = nestedSiteMap[currentRouteCodes[0]];
8484
if (currentSitemap === undefined) throwPageNotFound(`Route ${location} not found`);
8585

8686
for (const routeCode of currentRouteCodes.slice(1))
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import * as R from "remeda";
2+
3+
namespace BackendAPISchemas {
4+
export type EmptyObject = Record<string, never>;
5+
6+
export type DetailedErrorSchema = {
7+
code: string;
8+
detail: string;
9+
attr: string | null;
10+
};
11+
12+
export type ErrorResponseSchema = {
13+
type: string;
14+
errors: DetailedErrorSchema[];
15+
};
16+
17+
export type FlattenedSiteMapSchema = {
18+
id: string;
19+
route_code: string;
20+
name: string;
21+
order: number;
22+
parent_sitemap: string | null;
23+
page: string;
24+
};
25+
26+
export type NestedSiteMapSchema = {
27+
id: string;
28+
route_code: string;
29+
name: string;
30+
order: number;
31+
page: string;
32+
children: { [key: string]: NestedSiteMapSchema };
33+
};
34+
35+
export type SectionSchema = {
36+
id: string;
37+
css: string;
38+
39+
order: number;
40+
body: string;
41+
};
42+
43+
export type PageSchema = {
44+
id: string;
45+
css: string;
46+
title: string;
47+
subtitle: string;
48+
sections: SectionSchema[];
49+
};
50+
51+
export const isObjectErrorResponseSchema = (
52+
obj?: unknown
53+
): obj is BackendAPISchemas.ErrorResponseSchema => {
54+
return (
55+
R.isPlainObject(obj) &&
56+
R.isString(obj.type) &&
57+
R.isArray(obj.errors) &&
58+
obj.errors.every((error) => {
59+
return (
60+
R.isPlainObject(error) &&
61+
R.isString(error.code) &&
62+
R.isString(error.detail) &&
63+
(error.attr === null || R.isString(error.attr))
64+
);
65+
})
66+
);
67+
};
68+
}
69+
70+
export default BackendAPISchemas;
Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,8 @@
1-
import * as R from "remeda";
1+
import * as _BackendAPISchemas from "./backendAPI";
2+
import * as _BackendAdminAPISchemas from "./backendAdminAPI";
23

3-
namespace BackendAPISchemas {
4-
export type EmptyObject = Record<string, never>;
5-
6-
export type DetailedErrorSchema = {
7-
code: string;
8-
detail: string;
9-
attr: string | null;
10-
};
11-
12-
export type ErrorResponseSchema = {
13-
type: string;
14-
errors: DetailedErrorSchema[];
15-
};
16-
17-
export type FlattenedSiteMapSchema = {
18-
id: string;
19-
route_code: string;
20-
name: string;
21-
order: number;
22-
parent_sitemap: string | null;
23-
page: string;
24-
};
25-
26-
export type NestedSiteMapSchema = {
27-
id: string;
28-
route_code: string;
29-
name: string;
30-
order: number;
31-
page: string;
32-
children: { [key: string]: NestedSiteMapSchema };
33-
};
34-
35-
export type SectionSchema = {
36-
id: string;
37-
css: string;
38-
39-
order: number;
40-
body: string;
41-
};
42-
43-
export type PageSchema = {
44-
id: string;
45-
css: string;
46-
title: string;
47-
subtitle: string;
48-
sections: SectionSchema[];
49-
};
50-
51-
export const isObjectErrorResponseSchema = (
52-
obj?: unknown
53-
): obj is BackendAPISchemas.ErrorResponseSchema => {
54-
return (
55-
R.isPlainObject(obj) &&
56-
R.isString(obj.type) &&
57-
R.isArray(obj.errors) &&
58-
obj.errors.every((error) => {
59-
return (
60-
R.isPlainObject(error) &&
61-
R.isString(error.code) &&
62-
R.isString(error.detail) &&
63-
(error.attr === null || R.isString(error.attr))
64-
);
65-
})
66-
);
67-
};
4+
namespace CommonSchemas {
5+
export const BackendAPI = _BackendAPISchemas;
686
}
697

70-
export default BackendAPISchemas;
8+
export default CommonSchemas;

packages/common/src/utils/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as R from "remeda";
22

3-
import BackendAPISchemas from "../schemas";
3+
import BackendAPISchemas from "../schemas/backendAPI";
44

55
export const buildNestedSiteMap: (
66
flattened: BackendAPISchemas.FlattenedSiteMapSchema[]

0 commit comments

Comments
 (0)