우리들의 또다른 집.
로컬호스트에서 매번 작업하고, 프론트페이지와 백엔드를 같이 만들던 나날은 이제 끝이다.
처음으로 리액트 분들과 백엔드 분들이 어떻게 협업을 하는지 본격적으로 알게된 주간이다.
나는 처음에 통신을 하게 됬을때, 리액트 분들이 어떤 페이지를 만들고, 우리가 그쪽에서 무언가 연결을 하고,
설정파일을 조작하고 하는 아주 어려운 작업인줄 알았다.
하지만 그게 내 오판이였다는걸 2시간만에 알게되었다.
약간의 해프닝이 생겨 원래 팀장이시던 분이 사정이 생겨 팀장에 공백이 생겼다.
따라서 이전에 팀장을 한 경험이 있으신 프론트팀 한분과 나 이 둘중에 한분이 팀장을 맡아야 했는데,
아무래도 프론트분이 팀장 역활까지 맡게되신다면 너무나 업무에 부담이 될것이 뻔했다.
그래서 바로 자청해서 팀장은 걱정 마시라고 했고, 다행히 작성한 팀 WA를 다들 만족하셔서 나 역시 나름 나쁘지 않은 스타트였던것 같다.
// const whitelist = [process.env.WHITE_LIST];
// const corsOptions = {
// origin: function (origin, callback) {
// if (whitelist.indexOf(origin) !== -1) {
// callback(null, true);
// } else {
// callback(new Error("!!!PERMISSION DENIED!!!"));
// }
// },
// };
app.use(cors());
app.use(express.json());
CORS(Cross-Origin Resource Sharing) 정책을 설정해 주는 부분은 약간 헷갈리면서도 어려웠는데...
일단 서버의 스웨거를 확인하기 위해 잠시 모든 서버로부터의 요청을 열어놓은 상태이다.
CORS는 Cross-Origin Resource Sharing의 줄임말로, 한국어로 직역하면 교차 출처 리소스 공유라고 해석할 수 있다. 여기서 “교차 출처”라고 하는 것은 “다른 출처”를 의미한다.
잘 생각해보면 이렇게 출처가 다른 두 개의 어플리케이션이 마음대로 소통할 수 있는 환경은 꽤 위험한 환경이다.
클라이언트 어플리케이션, 특히나 웹에서 돌아가는 클라이언트 어플리케이션은 공격에 너무 취약한 친구이다.
당장 브라우저의 개발자 도구만 열어도 DOM이 어떻게 작성되어있는지, 어떤 서버와 통신하는지, 리소스의 출처는 어디인지와 같은 각종 정보들을 아무런 제재없이 열람할 수 있지 않은가?
따라서 웹생태계에선 최소한의 안전장치로 SOP(Same-Origin Policy)와 CORS가 존재한다고 생각하면 편하다.
클라이언트 어플리케이션이 다른 출처의 리소스를 요청할 때는 HTTP 프로토콜을 사용하여 요청을 보내게 되는데, 이때 브라우저는 요청 헤더에 Origin이라는 필드에 요청을 보내는 출처를 함께 담아보낸다.
Origin: https://mccshop.shop
여기서 이전에 내가 구현한것처럼 OPTION으로
프리플라이트(Preflight) 방식을 사용하여 먼저 보내줄 수 있다.
이 방식으로 요청할 시, 브라우저는 요청을 한번에 보내지 않고 예비 요청과 본 요청으로 나누어서 서버로 전송한다.
이때 브라우저가 본 요청을 보내기 전에 보내는 예비 요청을 Preflight라고 부르는 것이며,
이 예비 요청에는 HTTP 메소드 중 OPTIONS 메소드가 사용된다. 예비 요청의 역할은 본 요청을 보내기 전에 브라우저 스스로 이 요청을 보내는 것이 안전한지 확인하는 것이다.
즉 먼저 OPTION을 통해 예비 요청을 보낸 후, 응답에 담아준 허용 정책을 비교한 후, 이 요청을 보내는 것이 안전하다고 판단되면 같은 엔드포인트로 다시 본 요청을 보내게 된다. 이후 서버가 이 본 요청에 대한 응답을 하면 브라우저는 최종적으로 이 응답 데이터를 자바스크립트에게 넘겨준다.
또한 응답에 관련하여 CORS 정책 위반으로 인한 에러는 예비 요청의 성공 여부와 별 상관이 없다.
브라우저가 CORS 정책 위반 여부를 판단하는 시점은 예비 요청에 대한 응답을 받은 이후이기 때문이다.
물론 예비 요청 자체가 실패해도 똑같이 CORS 정책 위반으로 처리될 수도 있지만, 중요한 것은 예비 요청의 성공/실패 여부가 아니라
“응답 헤더에 유효한 Access-Control-Allow-Origin 값이 존재하는가”
이다. 만약 예비 요청이 실패해서 200이 아닌 상태 코드가 내려오더라도 헤더에 저 값이 제대로 들어가있다면 CORS 정책 위반이 아니라는 의미이다.
더 많은 CORS에 관한 이야기는
이곳을 보면서 더 공부를 해야겠다.
다행히 프론트분들과의 첫통신.
'HeloHalloween!'이 메세지가 서버쪽에서 확인되고, 클라이언트단에서도 확인이 되었을때 정말 엄청난 희열을 느꼇다.
따로 무언가를 설정하는 것이 아니라 서버에게 Axios를 사용하여 요청을 하면 된다는 그 자체를 내가 잠시 생각을 못했던것 같다.
아마 이걸 좀더 쉽게 생각했다면 이전 프로젝트에서는 리액트와 nodejs를 사용해서 해보지 않았을까 하는 아쉬움도 남는다
app.use('/user', [userRouter]);
app.use('/post', [postRouter]);
app.use('/reply', [replyRouter]);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDoc));
정말 간단하게 라우트 처리도 되고 api요청에 맞게 움직이고...
Router.get('/postlist', async(req, res) => {
try {
const postList = await Board.find({postingDel: 1}).sort("-postingDate");
res.status(201).json({ postList : postList });
} catch (err) {
res.status(400).send({
errorMessage: '해당 게시물을 더이상 찾을 수 없습니다.'
})
}
})
그저 명시하고 url를 정확하게 입력하고 cors도 완벽하다면 요청하게된다...
정말 놀라움 그 자체 엿다...
맨날 로컬호스트만 처리햇는데
통신을 통해 원하는 데이터를 특정한 형식으로 보내주는 이 동작의 흐름 자체가 나를 또다시 황홀경에 빠트릴뻔했다.
지금부터 써내려가는 글은 감정이 너무나 충만하고 압도적인 감사함밖에 없는 그때를 생각하며 써내려간 글이기에 약간의 과장이 존재할 수 있습니다
프론트앤드분들에게 내 모든 백엔드 코드가 찬미하는모습
프론트앤드분들이 리덕스로 데이터를 가져와 그려주는모습
그저 완벽함의 극치.
화면이 그려지고 백엔드에서 가져온 데이터로 와이어프레임을 토대로 화면을 그려주시는 프론트앤드분들의 엄청난 노고.
세분이서 합을 맞추며 여러개의 컴포넌트들을 하나의 뷰로 그려줄때의 그 아름다움
막히시더라도 절대로 포기하지않으시고 세분의 지혜로운 머리를 맞대어 하나의 해결책을 내시는 그 모습을 옆에서 보고있자면
그저 태양앞의 반딧불이요, 봉황앞의 참새가 되어버린다.
이렇게 고생하시면서 화면을 그려주시는 프론트분들을 위해 백엔드가 해야할 일은 무엇일까?
바로 완벽하게 원하시는 데이터를 가공하고, 필요한 API를 백엔드단에서 최대한 처리한 후 넘겨드리는것이다.
로그인처리, Validation체크, 수없이 많은 자잘자잘한 처리들을 서버단에서 처리할 수 있도록 하여 절대로 프론트분들이 백에서 일어나는 문제로 진척도에 문제가 생기면 안됬다.
그렇기에 만약 서버에러나 원하는 형식의 데이터를 불러오지 못햇을 경우 내 등에서는 조금씩 식은땀이 났다.
감히 지금 내가 프론트분들이 고생하시면서 그리는 화면에 더럽게 가공된 데이터를 남기거나 로그를 찍어내리거나 이상한 형식의 데이터를 보내서 프론트엔드분들의 길을 막아버린다?
그것은 지금 천인공노할 일이다.
이것은 나의 어쩔수없는 조심성으로 벌어지는 일이였다.
백엔드의 API는 사실 기본적인 뼈대는 최소 2시간이면 완벽하게 만들어 낼 수 있으나
어찌 감히 통신도 되지 않았고 원하는 데이터가 내려가지도 않았는데 API가 완성이 되었다 평할수 있겠는가.
그렇기에 나는 일단
다음과 같은 로직을 생각하고 빠르게 실행했다.
프론트앤드의 요청이 잘못되어도 항상 백앤드를 의심하자
라는 마인드를 명심하며 했다.
팻핑거와 같은 변수 실수. 구조분해할당 실수. ID확인 실수와 같은 자잘자잘한것때문에 통신에 실패할 수 있었기 때문이다.
다행히 백엔드는 좋은분이 계셔서 그분과 같이 이야기 하며 백엔드를 만들어 나갔다.
하지만 조금 힘들었던것은 아마 Git에대한 부족한 이해.
내가 총대를 매고 백엔드의 깃을 관리했으나, 브랜치와 Merge의 실수가 종종 있어서 서버를 괴롭히던 부분도 있었고,
문법적 오류와 변수 처리의 미스로
프론트 앤드분들이 원하시는 데이터를 잘못 날려드린적도 많았다.
안다고 자만하지말고 좀더 완벽하게 나아가봐야한다.
그리고 이번 프로젝트는 한번 Mysql을 사용하여 해보고싶었으나, 시간적 미스사항으로 결국 포팅하는데는 실패했다. 완벽하게 스키마를 짜지 않아 추가적으로 데이터를 넣고 넣고 해야했기에, mysql을 사용하기에는 조금 에로사항이 많았다.
그래서 아마 시간이 될때 지금 완성한 프로젝트의 데이터베이스를 몽고디비에서 Mysql로 바꾸어볼 예정이다.
매일 아침 10시, 밤 10시에 회의 할때마다 힘든 이야기 안하시고 다들 긍정적인 이야기 해주셔서 감사합니다
진척도 관리 이야기 할때마다 부담감으로 느끼실수 있으셨던 부분들이 존재했겠지만, 오히려 그것을 뛰어넘는 진행을 보여주셔서 정말 감사합니다.
비록 어쩔수 없는 상황이 되어 다시 맡게된 팀장이였으나,
그래도 최대한 여러분들과 프로젝트의 진행을 잘 진행 했던것같아 저역시 매우 기쁩니다.
부족했던 부분이 많은 팀장이였다.
하지만 다른분들은 다행히 좋게 봐주셔서 이렇게 분에 넘치는 고마움도 받았다.
지금으로부터 약 한달전, 처음 팀장을 맡았을때가 생각난다.
이때는 정말 너무나도 내가 많이 부족한 부분이 많았다.
그때 나는 다짐했었다.
다음에 팀장을 맡게 된다면 내가 힘들어 쓰러지는 상황이 있어도, 단 한명의 낙오자나 힘들어하는 분은 절대 없도록 만들어버리자고.
그렇게 다짐을 했고,
이렇게 한달뒤 내 다짐을 다시 확인할수 있게 되었다.
어제 제출을 끝나고 팀원들과 즐겁게 마지막 이야기를 하며 폭팔하던 감정들을 어느정도 추스리고 나에게 물어보았다.
나는 정말 괜찮았던 팀장이였을까?
이번에는 조금의 자신감을 담아 말하고싶다
아마 그랬던것 같다고