-
미니 게시판에 서버 추가짧은경험기 2023. 3. 21. 15:32
목적
이전에 만든 미니 게시판에 서버를 붙인다.
목표
- node.js, express를 이용하여 서버를 구현하고 mysql을연동한다.
- 기존의 미니 게시판을 서버와 연동한다.
과정
데이터베이스
db는 mysql로 하고, 따로 설치없이 docker를 이용하여 이미지를 띄워보기로 했다. mysql은 익숙하기도 하고 많은 사람들이 사용하여 자료 찾기가 쉬울 것 같아서 선택했다. 서버를 배포할 것이므로 docker를 사용하면 로컬에 설정한 내용을 기반으로 세팅하기 용이하지 않을까 싶었다. docker에 mysql 공식 이미지와 설명이 있어 이를 활용하였다. 링크에 있는 yml파일 예제에 몇가지를 추가하였다.
- volums: 저장한 데이터를 영속적으로 저장하기 위해 사용하였다. 도커에서 volums를 이용하여 매핑된 로컬 디렉토리에 데이터를 저장할 수 있다.
- container_name: 도커 컨테이너의 이름을 지정한다.
- envrionment: 환경 변수를 지정하면, 도커 컨테이너를 실행하면서 설정이 자동으로 적용된다.
yml 파일은 다음과 같다. 유념할 것은 adminer의 기본 포트 8080은 고정인 부분이다.
version: "1" services: db: image: mysql:latest container_name: mini-bbs-db command: --default-authentication-plugin=mysql_native_password restart: always ports: - "5051:3306" environment: MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}" MYSQL_DATABASE: "${DB_NAME}" MYSQL_USER: "${DB_USER_ID}" MYSQL_PASSWORD: "${DB_USER_PASSWORD}" volumes: - ./mysql:/var/lib/mysql adminer: image: adminer:latest container_name: mini-bbs-db-adminer restart: always ports: - "5052:8080" # adminer의 기본 포트 8080은 고정이다
서버
- node.js에 타입스크립트와 익스프레스를 이용하여 서버를 구현했다. 포스트맨을 테스트용 클라이언트로 삼아 진행했다.
- 서버가 받는 HTTP 메시지를 처리할 때, 동적인 데이터를 어떻게 취급할지 고민이 있었다. 예를 들어, 클라이언트가 HTTP 요청을 보낸다고 가정해보자. 포스트 메소드를 이용하고 메시지 바디에 json형식으로 데이터를 보내기로 약속했다면, 서버에선 다음과 같은 사항들을 해결해야 한다.
- 약속했던 대로 json 형식으로 데이터가 왔는지 확인
- 데이터에서 기대했던 키가 존재하는지 확인.
- 데이터에서 기대하지 않은 키가 있다면 제거.
- 밸류의 타입이 적절한지 확인.
- 밸류의 길이(댓글의 길이 제한 등)나 형식(이메일, 패스워드 등)이 적절한지 확인.
- 2의 문제를 효율적으로 해결하기 위해 class-transformer, class-validator 라이브러리를 사용하였다.
- class-transformer는 plain object를 클래스로, 클래스를 plain object로 변환하는 것을 도와주는 라이브러리이다. 변환 과정에서 조건을 주고 프로퍼티를 포함하거나 제거할 수 있다.
- class-validator는 클래스를 검증하는 것을 도와주는 라이브러리이다. 프로퍼티가 존재하는지, 프로퍼티의 값은 적절한지 등을 검증할 수 있다.
- 서버에서 DB에 접근하는 방법을 생각했다.
- 익스프레스는 라우터를 정의하고, 미들웨어와 컨트롤러를 라우터에 등록한다.
- 컨트롤러에서 클라이언트에서 받은 데이터를 검증하고 가공하여 디비와 연동해야 했다.
- 컨트롤러에서 모두 다 처리하면, 컨트롤러가 너무 비대해지고 복잡해진다.
- DB와 서버 사이에서 데이터를 다루는 독립된 레이어가 필요했다.
- 이 역할을 하는 객체를 DAO라고 하고 레이어 간에 데이터를 주고받을 땐 DTO라고 하여 처리하는 구조가 있었다.
- 컨트롤러 코드를 수정하여 게시글과 댓글을 위한 DAO 클래스를 만들어 활용하였다. 서버 안에서, 서버와 클라이언트 사이에 데이터를 주고받기 위해 DTO를 사용하였다.
- 서버가 받는 요청을 확인하기 위해 컨트롤러 마다 로그를 하나씩 남겼었다. 미들웨어로 만들까 하다가 찾아보니 morgan이라는 미들웨어가 있어서 사용하였다. 콘솔로도 남기고 파일로도 남길 수 있게 적용하였다.
클라이언트
- 기존 클라이언트는 댓글과 게시글을 localStorage에 저장하였다. 앱을 시작하면서 데이터를 생성하고 context api를 이용하여 하위 컴포넌트에서도 접근할 수 있도록 했었다. 새로운 댓글과 게시글을 추가할 때, localStorage에 업데이트하기 위한 코드 등이 있었다.
- 관련 코드를 모두 삭제하고 Fetch api와 useEffect 훅을 사용하는 쪽으로 코드를 수정하였다.
- CORS 에러가 발생하였다. 왜 발생했을까? 개발한 페이지를 실행할 때, npm run start 커맨드를 사용한다. 브라우저는 웹팩데브서버(로컬호스트 3,000번)에서 페이지를 받아온다. 데이터를 주고받는 api 서버는 로컬호스트 5,050번 포트를 사용한다. origin이 다른 것이다. 오리진은 프로토콜, 도메인 이름, 포트를 종합하여 만든 식별자이다.
- 브라우저와 서버 간의 통신은 SOP 규칙을 따른다. 동일한 오리진만을 허용하는 것이다. CORS는 SOP 규칙에 벗어나지만, 클라이언트와 서버 모두 예외적인 상황임을 헤더로 표시하고 통신을 진행하는 것이다.
- 클라이언트에서 해결할 방법으로는 프록시 설정이 있다. package.json에 proxy 옵션을 설정해주는 것이다.
- fetch api에서 요청하는 주소를 /api/post/all처럼 호스트 없이 경로만 작성한다.
- 클라이언트는 페이지를 내려준 웹팩데브서버에 요청하게 되고, 웹팩데브서버는 프록시로 설정해둔 서버에 요청한다. 그리고 서버로부터 데이터를 받아 클라이언트에 내려준다.
- CORS는 브라우저와 서버 간에 발생하므로, 브라우저에서 서버에 직접 요청하지 않고 서버에서 다시 서버로 요청하도록 우회하는 것이다.
- 서버에서는 CORS 관련 헤더인 Access-Control-Allow-.. 등의 헤더를 직접 설정해서 해결할 수 있다.
- cors 미들웨어를 사용하여 해결할 수도 있다. 이러한 미들웨어는 CORS 관련 헤더 설정을 대신해준다.
결과
참고
'짧은경험기' 카테고리의 다른 글
서로 다른 프로젝트에서 코드를 공유하기 (0) 2023.03.25 node.js + typescript 디버그 모드 실행하기(웹스톰) (0) 2023.03.22 미니 게시판 (0) 2023.03.19 업무일지를 지속적으로 써본 소감 (0) 2022.06.06 글 쓰는 시즌이 또 끝났다. (0) 2022.01.15