백엔드 마무리?
미래에서 다시보는 입장에서 백엔드가 끝났던 것은 아니었습니다. 하지만 적어도 이당시는 백엔드 작업이 대부분 달성한 것 같아서 프론트엔드를 착수하면 될 것이라고 착각하고 있었습니다.
로그아웃 미들웨어
로그아웃 기능이 없었고 기능을 찾는 과정에서 유용한 자료를 찾았습니다.
async function signout({ cookies, response }: Context) {
try {
const expires = new Date();
cookies.set('user', null, { expires });
response.status = 204;
response.body = null;
} catch (error) {
response.status = 400;
response.body = {
success: false,
msg: `${error}`,
};
}
}
비교적 간단하게 구현했습니다. access token은 클라이언트 사이드에서 처리하는 것이 좋을 것 같습니다. 자원의 접근을 막이 위해 많은 인증을 요구하는 로직은 이상합니다.
API 명세
API 명세서에서 다른 더 좋은 모범이 있었습니다.
사용자 비밀번호를 평서문으로 저장한다는 것이 치명적인 문제가 되고 있습니다. 하지만 그것은 API 명세서를 잘 작성한다는 컨텍스트와 무관합니다.
회원관리와 관련된 다양한 API를 제공하고 있습니다. 이부분은 보고 배울 점입니다.
사용하고 있는 서비스도 궁금하지만 엄청 긴 명세서에 적합해보이는 형식입니다.
그리고 요청응답 예시 코드가 좋아 보입니다. 마크다운 형식에 적합해 보입니다.
토큰 갱신에 대한 명세
일단 access token이 만료되어 있고 auth 외 요청을 보내면 갱신할 token으로 응답하기로 했습니다. 상당히 단순한 보안 정책으로 시작하고자 합니다.
카카오 로그인 명세서를 확인해보니까 갱신요청을 따로 하고 갱신할 token을 받고 갱신하고 다시 요청하는 것이 일반적인 것 같습니다. 나중에 수정하도록 하겠습니다. 갱신 요청에 대한 API를 추가로 구현해야 할 것 같습니다. 그리고 요청 - 만료 응답 - 갱신 요청 - token 응답 - token 갱신 - 재요청 순서로 처리하도록 할 것입니다. 하지만 이번 버전은 아닙니다.
data routing
// Routes.tsx
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import Layout from './GlobalLayout';
import {
Cards,
Deck,
Landing,
NotFound,
Setting,
SignIn,
SignUp,
} from '../pages';
import { ROUTE_PATHS } from '../constant/config';
/**
* 참고 자료
* @see https://github.com/WANTED-TEAM03/pre-onboarding-10th-1-3/blob/main/src/routes/Routes.tsx
* @see https://github.com/wanted-frontedend-team5/pre-onboarding-10th-1-5/blob/main/src/router/Router.jsx
*/
const routes = createBrowserRouter([
{
path: ROUTE_PATHS.WELCOME,
element: <Layout />,
children: [
{ index: true, element: <Landing /> },
{ path: ROUTE_PATHS.SIGN_IN, element: <SignIn /> },
{ path: ROUTE_PATHS.SIGN_UP, element: <SignUp /> },
{ path: ROUTE_PATHS.CARDS, element: <Cards /> },
{ path: ROUTE_PATHS.DECK, element: <Deck /> },
{ path: ROUTE_PATHS.SETTING, element: <Setting /> },
],
errorElement: <NotFound />,
},
]);
function Router() {
return <RouterProvider router={routes} />;
}
객체 관계를 갖는 것이 올바른 컴포넌트 관계를 나타냅니다. 과거에는 JSX로 작성했었습니다. 비교적 최근에 적용하는 패턴입니다. Remix에 영감을 받았다고 합니다.
// GlobalLayout.tsx
import { Global } from '@emotion/react';
import GlobalStyle from '../styles/Reset';
import { Navbar } from '../Components';
import { Outlet } from 'react-router-dom';
/**
* @see https://github.com/WANTED-TEAM03/pre-onboarding-10th-1-3/blob/main/src/routes/_globalLayout.tsx
*/
function Layout() {
return (
<>
<Global styles={GlobalStyle} />
<Navbar />
<Outlet />
</>
);
}
Outlet
이 children
역할을 비슷하게 합니다.
// constant/config.ts
export const BASE_URL = 'https://flash-card-backend.deno.dev/api';
export const API_URLS = {
CARDS: '/card',
SIGN_IN: '/auth/signin',
SIGN_UP: '/auth/signup',
};
export const ROUTE_PATHS = {
WELCOME: '/',
SIGN_IN: '/signin',
SIGN_UP: '/signup',
CARDS: '/cards',
DECK: '/deck',
SETTING: '/setting',
};
마지막 상수 객체는 컨텍스트와 무관하지만 data router 스타일로 리팩토링에 성공했습니다.