Node.js REST API DB Sync


*데이터베이스 연동

일반적인 백엔드 구조


지금 까지 했던 작업을 Client, Server, Database 중에 Server부분을 만들었음. Client에서 요청하는 것은 curl 사용하거나 모카 테스트로 진행했음.


남은 것은 가장 오른쪽에 있는 database 부분이다. 백에드에서 database 직접 만드는 것은 아님.

다양한 데이터베이스 프로그램이 있는데 그중 MySQL 사용할 것이다. MySQL 우리 컴퓨터에 개발용으로 설치하고 Server에서는 단지 데이터베이스에 연결하는 것이다.


*MySQL

설치


$ sudo apt-get install mysql-server


mysql 설치한 서버를 구동해야 한다. mysql 서버를 데몬이라고도 하는데 리눅스에서 말하는 데몬 혹은 서비스와 같은 것이다. 서버에서 백그라운드에서 실행중인 프로세스를 데몬이라고 한다. 로컬에서도 개발용으로 MySQL데몬을 실행해야 한다.


$ mysql.server start

반대로 종료할때는 

$ mysql.server stop


우분투에서는


이렇게 한다.


접속명령어는


$ mysql -u root -h localhost -p


mysql 명령어의 -u옵션은 서버 접속 계정을 넣을 사용하는데 기본 값인 root 사용했다. -h 옵션은 서버 접속주소를 설정하는 옵션인데 우리는 로컬 컴퓨터에 구동중인 mysql서버에 접속하므로 localhost 사용했다. 마지막 -p 옵션을 비밀번호를 입력하기 위한 기능이다. 명령어를 실행하면 비밀번호를 입력하도록하는데 root 입력하고 접속한다. 




DB목록 조회


DB 생성


DB선택



여기서 부터는 mysql명령어를 사용하지 않아도 된다.


*Sequelize

노드 코드에서 mysql 접속해서 이런 저런 쿼리문을 실행할 때는 노드 코드로 만든 mysql 패키지가 ㅣㄹ요하다. 그것이 ode-mysql이다. 이것을 우리 프로젝트에 추가해서 쿼리문을 직접 실행시킬수 있음.

이를 ORM(object relational mapping)이라고 하는데, ORM 사용하면 쿼리문을 모르더라도 자신이 사용하는 프로그래밍 언어로 데이터베이스에 명령을 내릴 있다. 노드에는 sequelize라는 orm라이브러리가 있음.


$ npm i sequelize —save


*Model

서버에서 하나의 자원을 정의할 그것을 모델이라고 한다. 우리는 지금까지 User라는 자원을 사용했다. 이것이 User모델이다. 모델은 데이터베이스의 테이블과 1:1 매칭된다고 보면 된다. 그러면 데이터베이스에 User테이블이 있어야 . User테이블을 만들기 위해, 다시말하면 User모델을 만들기 위해 Sequelize 도움을 받아야 한다.


모델을 만드는 역할을 하는 models.js 파일을 만들자.




 sequelize모듈을 가져와 Sequelize상수에 할당했다. 그다음엔 Sequelize객체를 하나 만들어 sequelize 상수에 할당했다.

Sequelize객체를 만들 때는 3개의 파라미터가 필요한데 데이터베이스 이름, 접속 계정명, 비밀번호 순이다. 순서대로 문자열로 파라미터를 넘겨주면 sequelize객체를 얻을 있다.

객체가 제공하는 메소드중 define()함수를 이용해 모델을 만들 있음.



define() 함수의 첫번째 파라미터가 데이터베이스에 만들어질 테이블 이름이다.


다음에는 테이블의 세부사항을 객체 형식으로 정의해야한다. 이전에 유저 객체에는 id name 있었는데 둘을 여기서 정의하면 된다.

name: Sequelize.STRING name컬럼을 정의하는 코드이다.Sequelize.STRING 상수를 이용해 name값이 문자열임을 정의했다.

그럼 id 어디에?

-> sequelize 기본적으로 id 만들어 준다.


게다가 createdAt, updatedAt 이라는 칼럼도 자동으로 만들어 준다. 컬럼들의 역할은

테이블안에 데이터를 row라고 하는데 row 생성될 마다 createAt 시간정보가 기록된다. 그리고 row 변경될 때마다 updatedAt컬럼값이 변경된다.


마지막으로 module.export해준다.



*DB Sync

sequelize객체가 제공하는 메소드 중에는 모델을 정의하는 define()외에도  sync()라는 메소드가 있다. 함수를 실행하면 sequelize객체에 연결된 데이터베이스에 우리가 정의한 모델들을 테이블로 생성하는 기능이다.

이러한 작업은 서버가 구동될 한번만 호출되면 된다. 그래서 서버의 시작점인 app.js 만들도록 한다.


  • 다음과 같은 오류가 출력되는 경우



$ npm i install mysql2 —save

  • 다음과 같은 오류가 출력되는 경우


$ sudo mysql -u root -h localhost -p
> use mysql
> update user set authentication_string=password(‘’), plugin=‘mysql_native_password’ where user=‘root’;


성공


app.listen()으로 서버가 구동된 다음에 콜백함수가 동작하면 ‘Example app listening on port 3000!’라는 메시지를 콘솔에 출력하게 된다.

그리고 나서 방금 만들었던 models 모듈의 sequelize객체를 가져와서 sync() 함수를 실행한다. 데이터베이스에 테이블을 만들기 위해서다.


그런데 sync()함수에 {force: true}옵션을 넘겨주었다. force라는 속성에는 불리언 데이터를 설정할 있는데 true 경우 sync()함수가 실행되면 무조건 테이블을 새로 만드는 옵션이다. 반대로 force 값이 false 경우에는 데이터 베이스에 테이블이 있을 경우 다시 만들지 않는 기능이다. 지금은 개발용이기 때문에 {force: true} 설정했지만 실제 운영중인 서버라면 반드시 {force: false} 옵션으로 실행해야 한다.



방금 만들었던 users 테이블이 생겼다. 그런데 define()함수로 테이블명을 user 했는데 위의 사진은 users 되어있다. sequelize에서 자동으로 변환해서 만들어 준것이다.


테이블 정보 확인


id 값은 sequelize 자동으로 생성한 컬럼이다. 프라이머리 키로 설정되어 row 생성될 마다 자동으로 id값이 증가한다.

name 우리가 정의한 컬럼이다. sequelize.STRING 값으로 정의했는데 varchar(255) 설정된 것을 확인 해볼 있다.

그리고 createdAt updateAt sequelize 자동으로 만들어준 컬럼이다. datetime형식으로 되어있음.


*컨트롤러에 데이터베이스 연동


Sequelize 로컬에 구동중인 데이터베이스와 api서버를 연결했다. 그리고 우리가 모델링한 테이블까지 데이터베이스 안에 만들었음.


이제는 테이블에 데이터를 넣거나 조회하거나 삭제 그리고 업데이트하는 작업을 차례이다. 이것은 CRUD기능이라고 한다. create, read, update, delete  기능을 말하는 . api 기능이 데이터베이스의 데이터를 crud하는 것이라 보면 된다.

지금까지는 데이터를 users  배열에 넣고 개발했는데 이제는 데이터베이스를 이용한다.


*create

먼저 user컨트롤러에서 models 가져온다.

/api/users/user.controller.js



테이블이 아직은 비어있기 때문에 먼저 테이블에 넣는 create() 사용해보자


name파라미터를 검증하는 부분까지는 이전코드와 같다. name값이 확보되었다면 models모듈을 이용해 테이블에 데이터를 추가하는 것이 남았음. 

models.User객체는 crud 해당하는 메소드 들을 제공하는데 그중 create() 메소드는 테이블에 데이터를 추가하는 기능을 한다. 파라미터로 넣은 데이터를 객체 형식으로 넘겨준다. 

name컬럼에 name상수값을 넣어줬다.

그리고 then함수가 동작하면 콜백함수의 user파라미터로 테이블에 생성된 row 나온다. 이것을 요청한 클라이언트에 그대로 전달해 주면 된다.


*read

데이터를 조회하는  api 컨트롤러는 index(), show() 메소드가 있다.


index() 모든 사용자 목록을 조회하는 것이기 때문에 테이블 전체 데이터를 불러와야한다.

models.User 객체의  findAll() 메소드를 사용하면 테이블의 전체 데이터를 불러올 있다.




show() 특정사용자를 id 조회하는 역할을 한다. models.User 모델은 findOne() 함수로 조건을 줘서 데이터를 조회한다. where 라는 부분에 id컬럼의 조건값을 설정하여 넘겨준다. 함수가 실행되면 콜백함수의 파라미터로 조회한 user객체가 응답된다. 만약 user값이 비어있다면 테이블에서 id 해당하는 데이터를 찾지 못한것. 이경우 404 상태코드로 응답한다. 성공한경우에는 json()함수로 응답해준다.



*delete

삭제할 때는 destory()메소드를 사용한다. id기준으로 삭제하는 것이므로 where 이용해 파라미터를 넘겨준다.



*update

update 조금 특별하다. 테스트 코드를 먼저 작성하고 컨트롤러 함수를 만들 이다. 이렇게 코딩하는 방법을 tdd(test-driving develop) 개발방법론이라고 한다.

테스트 코드를 api/user/user.sepc.js 추가하자.



update api 호출하면 200 상태코드가 응답되는지 체크하는 코드이다. 테스트를 돌려보면 당연히 실패가 나올 것이다.

  • 블로그에서는 실패가 출력된다고 했는데 나는 이상하게 passing 출력된다. 이유가 뭘까?


밑에 댓글을 보니 이런 내용이 있다.





다시 블로그의 내용으로 돌아가서 

404에러 메세지가 나오는데 라우팅 설정을 하지 않았기 때문 그럼 테스트를 통과할 있도록 코드를 추가해 볼것이다. 먼저 /api/user/index.js 파일에 해당 api 대한 라우팅 설정을 추가한다.


PUT /users/:id 요청이 들어올 경우 update 컨트롤러 함수가 동작하도록 설정했다.

api/users/user.controller.js파일로 이동하고 update 함수를 정의하자.


update()함수에서는 요청이 들어오면 send()함수를 이용해 200 상태코드만 응답하도록 변경하였다. 그리고 나서 다시 테스트를 돌려보면 테스트에 통과한다.



*중간점검   구조 정리

./

./app.js: 서버 구동 db sync
./models.js: db table row 정의

./api/users/

index.js: rest api  함수 초기화

user.controller.js: 실제 rest  api함수들의 동작을 정의

user.spec.js: test 구동을 위한 코드


  • 실행 CRUD 기능 동작 여부

    -GET /users


-GET /users/:id


-GET /users/:name

(구현 아직 안함)

-POST body={name: string}



-DELETE /users/:id




- PUT /users/:id 




-> update(PUT) 기능 동작

출처:  http://webframeworks.kr/tutorials/expressjs/expressjs_orm_two/




  • npm test 기능 동작 여부
    -GET, PUT


GET, PUT 이렇게 2개의 passing 떠야 하는데 현재 PUT 검사하는중 게다가 PUT 200 status response 중임.


-> 해결


원래 it.only( … ) 되어있던 코드를 

it( … )으로 변경함



-DELETE POST

DELETE POST TABLE length 변경하므로 코드 리펙토링 구현하도록 한다.


지금까지 만든 것은 https://github.com/kiryun/NodeJS_REST-API_tutorial 의 Second Commit에 올려놨다.


+ Recent posts