React.js Codelab 2016 – Express 와 React.js 를 사용한 웹 어플리케이션 만들기 (1)


시작하면서..

React.js 코드랩에 참여하신 모든 개발자 여러분! 환영합니다!

저희는 이제 배경지식을 어느정도 공부 한 상태이고, 이제 마지막 프로젝트를 진행해볼 차례입니다.

(코드랩 세션을 참석하지 못하셨다면, https://velopert.com/reactjs-tutorials 에서 React 입문을 하고나서 이 강좌를 진행해주세요.)

이전에 만들었던 예제 프로젝트와는 달리 이번에는 조금은 멋진? 웹 어플리케이션을 만들어볼거에요.

미리보기 URL: https://memo.hoah.xyz/

몇몇 분들에게는 간단한 프로젝트가 될 수 도 있겠지만,

초보자들분들에게는 어쩌면 조금은 복잡한 프로젝트가 될 수도 있습니다.

 

만약에 코드랩 세션에서 시간이 부족하거나 도중에 막혀서 완성하지 못할시엔, 이 포스트를 참조하면서 프로젝트를 완성해보시길 바랍니다.

도중에 질문이 생기거나 하면 언제든지 물어봐주세요 (덧글 혹은 이메일)

 

강의를 시작하기전에, 작업환경을 설정해주시구요: https://velopert.com/1980

자, 그러면 강의를 시작하겠습니다 !


1. Express & React.js 설정하기

초기 프로젝트 CLONE 하기

Global Dependency 설치

babel-cli: 콘솔 환경에서 babel 을 사용 할 수 있게 해줍니다 (ES6 transpile)

nodemon: development 환경에서 파일이 수정 될 때마다 서버를 재시작해줍니다

cross-env: 윈도우 / 리눅스 / OSX 에서 환경변수값을 설정합니다.

 

Local Dependency 설치

express: Nodejs 웹 프레임워크

body-parser: JSON 형태의 데이터를 HTTP 요청에서 파싱 할 때 사용됩니다

 

Express 코드 작성 server/main.js

 

NPM 스크립트 수정 package.json

주의: 윈도우는 명령어가 다릅니다! 윈도우는 win_start / win_development 를 이용해주세요.

npm run build 를 실행하면 서버사이드 스크립트들을 build 폴더에 transpile 하여 저장하고 webpack 을 통해 클라이언트 코드를 build 합니다.

 

Webpack 개발서버용 설정파일 만들기 webpack.dev.config.js

development 환경과 production 환경에서 bundle.js 의 결과값이 다르기 때문에 개발환경 전용 설정파일을 따로 만듭니다

주의: 최근 react-hot-loader 가 업데이트 되어서, 그냥 설치하시면 “react-hot-loader”: “^3.0.0-beta.3” 가 설치됩니다.

설치 하실 때, npm install –save [email protected] 을 하시거나, 버전 3을 쓰고 싶다면 수정을 다음과 같이 하세요:

 

Webpack 설정파일 수정 webpack.config.js

기존의 필요없는 설정을 지웠습니다.

 

server 메인 파일 수정 server/main.js

development 환경일때 개발서버를 켜는 코드를 추가하였습니다.

 

체크포인트

앞으로 진행을 하다가 도중에 막히면 (해결을 하고 넘어가는게 좋지만) 계속해서 진행을 하기위하여 체크포인트로 “이동”을 할 수 있습니다.
현 상태를 체크포인트로 넘어가는 방법은 다음과 같습니다:

해당 섹션의 전체 코드를 확인하고자 한다면 https://github.com/velopert/react-codelab-project 에 들어가서

제목 없음

위와 같이 브랜치를 선택해주시면 됩니다.

2. MongoDB 설치

저희 프로젝트에서는 MongoDB 데이터베이스를 사용합니다.
MongoDB 를 설치하는 과정은 이 포스트 를 참고해주세요.

코드랩 세션에선 기본적인 MongoDB 에 대한 소개와 사용법을 설명해드렸었지만, 코드랩 세션에 참여하지 않은 분들은
MongoDB 강좌를 훑어보시길 바랍니다

 

3. 미들웨어 및 기타 모듈 설치

주의: 이 포스트에 나오는 코드 조각들에는 일부 코드(이미 작성된 부분)들이 생략되어있습니다.
필요한 부분만 적혀있으니, 적당한 위치에 코드들을 삽입/수정 해주세요

모듈 설치 및 적용 (i)

server/main.js

morgan: HTTP 요청을 로그하는 미들웨어

body-parser: 요청에서 JSON을 파싱할때 사용되는 미들웨어

 

모듈 설치 및 적용 (ii)

server/main.js

mongoose: mongodb 데이터 모델링 툴; MongoDB 에 있는 데이터를 여러분의 Application에서 JavaScript 객체로 사용 할 수 있도록 해줍니다.

참고: https://velopert.com/594

express-session: express 에서 세션을 다룰 때 사용되는 미들웨어

참고: https://velopert.com/406

 

4. Backend – 계정인증 구현하기

디렉토리 구조 이해하기

models 디렉토리엔 mongoose로 만든 데이터 모델이 저장되어있고, routes 디렉토리엔 회원인증 / 메모 API 들이 저장되어있습니다.

 

account 라우터 생성 (server/routes/account.js)

회원가입 / 로그인 / 현재세션체크 API 를 담당할 account 라우터 입니다

먼저 틀만 짜놓고 나중에 구현합시다

 

api 루트 라우터 생성 (server/routes/index.js)

지금은 루트 라우터에서 account 라우터만 불러와서 사용하지만

나중에는 메모를 담당하는 memo 라우터도 불러와서 사용하게 됩니다

 

api 라우터 불러와서 사용 (server/main.js)

이렇게 서버 메인 파일에서 api 라우터를 불러오게 되면,

http://URL/api/account/signup 이런식으로 api 를 사용 할 수 있게 됩니다

 

mongoose 를 통한 account 모델링 (server/models/account.js)

account Schema 를 만들고 model 로 만들어서 export 합니다

Schema 와 Model 의 차이는, Schema 는 그냥 데이터의 ‘틀’ 일 뿐이구요, Model 은, 실제 데이터베이스에 접근 할 수 있게 해주는 클래스입니다

참고: http://mongoosejs.com/docs/guide.html

모델화르 할때 .model() 의 첫번째 인수로 들어가는 account 는 collection 이름이에요. 근데, 이게 복수형으로 설정이됩니다. 예를들어 account의 복수형은 accounts 이니 accounts 라는 컬렉션이 만들어지고 거기에 저장이 되는거죠. 컬렉션 이름을 직접 정하고싶다면 .model(‘my_account’, Account, ‘my_account’) 이런식으로 세번째 인수를 추가하여 전달해주면 됩니다.

 

bcryptjs 해쉬 모듈 설치

게정 인증을 구현하는데, 비밀번호를 그냥 plain text 로 저장하게하면 보안상 좀 허술하겠죠?

bcryptjs 모듈을 사용하여 비밀번호 보안을 강화합시다! 사용법: https://www.npmjs.com/package/bcryptjs#usage—sync

 

bcryptjs 적용하기 (server/models/account.js)

여기서, Schema 자체에 임의 메소드 두개를 정의해주었습니다.

이렇게 메소드를 만들어주면 나중에 모델에서 해당 메소드를 실행 할 수 있습니다

주의하실 점은 여기서는 arrow 메소드를 사용하시면 제대로 작동하지 않기 때문에 그냥 일반 함수형으로 작성하셔야합니다 (this binding 오류)

 

회원가입 구현: POST /api/signup (server/routes/account.js)

mongoose 의 사용법은, mongodb 의 명령어와 매우 비슷합니다.

새 모델을 만들때는, 객체를 생성해주고, save 메소드를 통하여 값을 저장합니다.

 

로그인 구현: POST /api/signin (server/routes/account.js)

express session 을 다루는건 매우 간단합니다.

따로 해야 할 건 없고, req.session 을 사용해서 그냥 객체 다루듯이 하면 됩니다

 

세션확인 구현: GET /api/getInfo (server/routes/account.js)

세션확인이 필요한 이유는, 클라이언트에서 로그인 시, 로그인 데이터를 쿠키에 담고 사용을 하고 있다가,

만약에 새로고침을 해서 어플리케이션을 처음부터 다시 렌더링 하게 될 때, 지금 갖고 있는 쿠키가 유효한건지 체크를 해야 하기 때문입니다.

 

로그아웃 구현: POST /api/logout (server/routes/account..js)

현재 세션을 파괴 할 때는 req,session.destroy() 를 사용하면 됩니다.

간단하죠.

 

Express 에러처리 (server/main.js)

라우터에서 throw err 가 실행되면 이 코드가 실행됩니다

 

5. Backend – 메모 작성 / 수정 / 삭제 / 읽기 구현하기

Memo 모델 만들기 (server/models/memo.js)

 

Memo 라우터 만들기 (server/routes/memo.js)

계정인증부분 작성 할 때 처럼, 먼저 틀을 작성해두고 구현은 차차 하도록 하겠습니다.

 

API 라우터에 Memo 라우터 추가 (server/routes/index.js)

memo 라우터를 api 라우터에서 사용하도록 합시다. 이제 /api/memo 에다가 GET / POST / PUT / DELETE 등 메소드로 요청을 할 수 있습니다

 

작성기능 구현하기: POST /api/memo (server/routes/memo.js)

 

읽기기능 구현하기: GET /api/memo (server/routes/memo.js)

지금으로서는, 작성된 메모들을 최신부터 오래된것 순서로 6개만 읽어옵니다.

나중에, 무한 스크롤링을 구현 할 때는, 특정 _id 보다 낮은 메모 6개 읽기,
새로운 메모를 읽어올 때에는, 특정 _id 보다 높은 메모읽기,
그리고 유저를 검색할 때 사용 될 특정 유저의 메모 읽기 기능을 구현 할 것입니다.

 

삭제 기능 구현하기: DELETE /api/memo/:id (server/routes/memo.js)

 

수정 기능 구현하기: PUT /api/memo/:id  (server/routes/memo.js)

Backend를 작업하는건, NodeJS 를 처음 사용해보시는거라면, 익숙하지 않을수도 있지만,
하면 할수록 편해진답니다.

자, 이제 기본적인 Backend 구현이 끝났습니다.

(단, 아직 Backend 가 완전하게 끝난건 아닙니다, 아직 star 기능, 유저 찾기 기능, 페이징 기능이 남아있습니다)

우리가 지금 만든 Backend 를 토대로 React 어플리케이션을 만들어봅시다.

  • Seongkuk Park

    아직 mongoose 가 익숙치 않아서 복잡해 보이네요;

  • 안녕하세요. 최근 프로젝트에 react를 접목하면서 많은 도움이 되고 있습니다.
    다름 아니라 Webpack-dev-server 설정 파일 (webpack.dev.config.js) 의 프록시 설정이 최근들어 미묘한 변동이 있는 것 같아 댓글을 답니다.
    오늘 개인 프로젝트를 새로 git clone 떠서 npm3 install을 했더니 다음 코드의 프록시가 제대로 작동하지 않았습니다.
    proxy : {
    “*” : “http://localhost:3000”
    },

    그래서 좀더 찾아보니 webpack dev server 공식 github.io의 proxy 부분이 미묘하게 바뀌었더군요.
    // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server.
    // Use “**” to proxy all paths to the specified server.
    // This is useful if you want to get rid of ‘http://localhost:8080/’ in script[src],
    // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ).
    proxy: {
    “**”: “http://localhost:9090”
    },

    설정을 **으로 바꾼 뒤로는 다시 정상 작동합니다. 제 개인설정이 잘못 된 것일수도 있지만 혹여 확인해보시고 webpack.config 규격이 바뀐 것이라면 반영하는 것이 좋을 것 같아 알려드립니다.

    • 감사합니다! 이전에는 webpack-dev-middleware 를 구버전을 사용해서 됐었던거였네요.
      수정하겠습니다 🙂

    • 만약에 코드랩 중에 발견했으면 멘붕했을것같습니다…ㅋㅋㅋㅋ

  • 레미프

    음.. 근데 왜 main.js 에서 app 설정하는 내용이 없는거 같은데 제가 잘못안건가요?

    • Express 코드 작성 server/main.js

      에서 작성한 코드를 그대로 유지하면서 진행합니다. 헷갈릴수도있으니 조만간 수정하겠습니다.

  • ggoban

    api 라우터 불러와서 사용 (server/main.js)

    /* setup routers & static directory */
    import api from ‘./routes’;
    app.use(‘/api’, api);
    이렇게 서버 메인 파일에서 api 라우터를 불러오게 되면,

    http://URL/api/signup 이런식으로 api 를 사용 할 수 있게 됩니다.

    위부분은 아래 내용과 테스트 내용하고 비교해보면 http://URL/api/account/signup 이런형태가 맞는거죠??

    따라서 실습중인데 저는 express는 따로 분리하는걸 좋아해서 분리후 진행중입니다. 별 문제는 없겠죠??

    • * 수정되었습니다.

      이전엔 한 프로젝트에 진행 했었는데, 저도 따로 분리해서 관리하는걸 좋아합니다 ㅎㅎㅎ
      별 문제 없습니다 !

  • ggoban

    좀 백엔드에서 둘러봤는데 signin 할때는 session 에 정상적으로 logininfo 가 보이는데
    로그인 상태 확인시의 req 전체를 보면 session에는 비어있더라구요. 대신 req.sessionStore 안에 MemoryStore 쪽 sessions 에 저장이 되던데 ..
    버전의 문젠지 두갤 분리해놓은 문젠지.. 잘 모르겠네요 ㅠㅠ쥬륵

  • 류한경

    velopert 님! mongoose.Types.ObjectId.isValid 이게 디비에 _id 값이 존재하는가? 안하는가?를 알려주는건가요?

    • 해당 명령어는 주어진 id 가 제대로된 mongodb id 인지 형식을 확인해줍니다.
      예를들어 ‘asdf’ 이렇게만 전달해주면 false 가 되겠죠.

      존재유무는 확인해주지 않아요.

  • Sim Isaac

    webpack.dev.config.js에
    변경사항 있습니다. rename되었다고 하네요.
    OccurenceOrderPlugin -> OccurrenceOrderPlugin
    그리고 이마저도 default가 되었기 때문에 할 필요 없대요. 관련 링크는
    https://gist.github.com/sokra/27b24881210b56bbaff7#occurrence-order
    입니다.

    NoErrorPlugin도 마찬가지로 안 되는데,
    ->NoErrorsPlugin으로 바뀐 건지 오타난 것인지는 모르겠습니다. 아무튼 제가 올린 것으로 바꾸셔야 해요. 그리고도 webpack option validation error가 나고 있는데 그 이유는 좀 찾아봐야겠네요.

  • Gen happy

    github 에 있는 react-skeleton 이용해서 공부해도 되겠죠?
    설치 해도 안되어서요…
    css-loader 라은 브랜치는 scss를 사용하는건가요?