백엔드는 처음이라 두 번째 주제는 Express와 디렉토리
이다.
Nodejs 환경에서 서버를 구성하는 프레임워크는 Express
외에도 Koa.js
, Hapi.js
, Nest.js
등이 존재하지만, Express
가 가장 많이 사용되고 사용하기 쉽다고 알려져있다.
Express는 미들웨어, 라우팅을 사용해서 서버를 쉽게 구성할 수 있다.
미들웨어 함수는 요청 오브젝트(req), 응답 오브젝트 (res), 그리고 애플리케이션의 요청-응답 주기 중 그 다음의 미들웨어 함수 대한 액세스 권한을 갖는 함수입니다.
Express 공식 문서는 미들웨어를 위와 같이 설명하고 있다. 쉽게 말하자면 "서버에 도착한 요청(request)들이 응답(response)될 때 까지 거쳐가는 공통적인 처리장치"라고 할 수 있다. 이 역시 와닿지 않으니 예시를 들어보자.
서버가 처리하는 요청을 크게 구분하자면 비로그인 상태여도 가능한 것 / 로그인 상태여야 하는 것 두 가지로 나눌 수 있을 것이다. 토큰 방식의 인증 처리를 구현한 서버라는 가정하에, 로그인이 된 상태의 요청인지 확인하기 위해서는 해당 토큰의 유효성을 검사하고 그 결과에 따른 처리가 필요하다.
이 경우 해당 요청에서 token을 얻어내서, 유효성을 검사하고, 그 결과에 따라 통과시키거나 에러를 발생하는 등의 공통적인 처리를 하는 checkTokenMiddleware를 만들어서 사용할 수 있는 것이다.
이러한 미들웨어는 서버에 들어오는 모든 요청에 대해 적용할 수도 있고, 특정 라우터에만 적용할 수도 있다. 위의 예시의 경우 로그인이 필요한 요청들의 라우터에 등록해놓을 수 있을 것이다.
위의 로그인를 확인하는 것처럼, 여러가지 요청 처리 로직이 공통적으로 가지고 있는 로직을 수평 관심사 혹은 공통 관심사라고 한다. 미들웨어는 이 수평/공통 관심사를 일괄적으로 처리하는 함수
라고 다시 표현할 수 있을것이다.
URI(또는 경로) 및 특정한 HTTP 요청 메소드(GET, POST 등)인 특정 엔드포인트에 대한 클라이언트 요청에 애플리케이션이 응답하는 방법을 결정하는 것
// app.js
import express from 'express';
const app = express();
app.use('/api', apiRouter);
// auth.js
import { Router } from 'express';
const authRouter = Router();
authRouter.post('/signup', authController.signup);
authRouter.post('/signin', authController.signin);
express app
을 생성하고, use
메소드를 통해 app
인스턴스에 authRouter 미들웨어를 바인딩한다.
authRouter는 post 메소드 요청 중, 지정된 path에 해당하는 응답(signup, signin)을 두 번째 인자에 등록한 미들웨어로 처리한다.
.
`-- src
|-- config
|-- controllers
|-- database
|-- errors
|-- middlewares
|-- migrations
|-- models
|-- routes
|-- services
`-- uitls
환경 설정을 위한 폴더
데이터베이스 상위 폴더
데이터베이스의 각 테이블(모델)에 해당하는 파일들 모음
user, category, record등 실제 DB의 테이블 형태를 가지는 class 객체를 담아둔다.
sequelize를 사용했기에 테이블을 객체화할 필요가 있음!
다른 팀은 entity로 명명하기도 하는 듯
라우터 모음. path와 유사한 폴더 구조를 가진다
서버에 요청이 들어올 때 URI의 path에 따라 필요한 controller로 이어주는 역할만 한다.
중요한건 다른 처리 없이 요청과 그 처리를 담당하는 controller를 이어주는 역할만 한다는 것!
Request, Response를 담당한다.
Request 데이터를 가공하고, 필요한 service에 데이터를 전달한다
service의 처리에 따라 클라이언트에 Response하는 역할을 담당
비즈니스 로직은 service에게 맡긴다.
HTTP 관련 에러는 여기서 발생시켜야한다
비즈니스 로직을 담당한다.
서비스는 오직 비즈니스 로직 처리를 담당한다. 따라서 Requeest, Response를 전달 받지도 않고, 그 존재에 대해 알 필요도 없다
데이터베이스에 직접 접근하는게 아니라 data access layer
에게 접근 관련 처리를 맡기고 전달받은 값으로 비즈니스 로직을 진행한다.
또한 상태 코드 또는 헤더와 같은 HTTP 전송 계층과 관련된 것들을 반환하지도 않는다.
즉 에러가 발생하더라도 그 에러가 400인지 같은 코드 넘버를 발생시키는게 아니라 비즈니스 로직에 대한 에러만 발생시켜야 한다.
단, 우리팀은 편의를 위해 여기서 HTTP 에러를 발생시켰다..
data access layer. 데이터베이스와 통신하는 영역
데이터베이스에 접근해서 CRUD 동작을 하고 그 처리를 반환한다.
여기서 발생하는 에러는 모두 500에러로 처리되겠지만, 그렇다고 여기서 직접 500 에러가 담긴 에러 객체를 생성하는게 아니다 그 역할은 controller가 맡고 있다.
이 프로젝트 뿐 아니라 어디에서든 쓸 수 있는 범용성 있고 재사용 가능한 유틸들 모음
구체적인 에러 객체를 생성하기 위한 파일 모음
미들웨어를 모아두는 폴더