[Node.js] Mysql로 API를 만들고 Vue.js 연결

Lee Tae-Sung·2021년 9월 30일
0

Project

목록 보기
1/9

[Node.js] Mysql로 API를 만들고 Vue.js 연결 (signup, login)

1. 포스팅 개요

ssafy 특화 프로젝트로 빅데이터를 활용한 향수 추천 서비스를 개발.
signup & login을 Mysql, Node.js, Vue.js 를 연결해 서비스의 전체 흐름 개발. (오늘부터 게시판, QnA 개발 예정)

시작 동기(왠지 기록해두고 싶다...)

컨설턴트님의 추천으로 팀의 협업을 기능별로 나누기로 결정했다. 그리고 평소에 관심 있었던 node.js를 backend로 개발하기로 결심했다.

총 네가지 이유가 있는데,

  1. JS만으로 서비스 전체를 온전히 만들 수 있게 되는점

  2. 프론트엔드 개발자 직무인데 우대사항에 Node.js 경험이 있는 경우가 많음

  3. spring, django는 벡엔드에 많지만 node.js는 희소성이 있으리라

  4. 같이 일하며 배우고 싶은 향로님이 일하고 계시는 인프런이 node.js 를 이용하는 점

    홍선이의 약 세달 전쯤 말했던 "JS만으로 모든걸 할 수 있는 이런게 요새 뜨더라구요~" 에도 영향을 받았다ㅋㅋ

2. 어려움

우선 기억 저편에 숨겨두었던 벡엔드 지식을 꺼내와야했다.
=> ㅋㅋ 이건 뭐!

  1. Node.js 의 api가 아닌 js 프레임워크와의 연동

코딩애플에서 Node.js 강의를 들었다.
강의 목록에 MongoDB 연결, React 연동 등등이 있어 강의를 들으며 따라 쳐서 방향들만 바꿔주면 짠! 완성 될 줄 알았다.

아니 그런데 기껏 공부 다 했더니
;; Node.js는 Vue.js(React.js)와 config를 바꿔주는 방식으로 손쉽게 연동을 시켰다.

그래서 덕분에 MongoDB를 이용하는 이유, Node.js를 쓰면 얼마나 편한지를 알게됐는데.

그건 좋은데 지금 나는 docker 없이 spring, django가 함께 있기 때문에 api를 굳이 사용해야했다. 그래서 하나하나 일일히 구글링해서 찾아 조합..

  1. Node.js에서 api 만드는건 비주류?

    자료를 찾아보며 자료들이 나오기는 하는데 공식문서 같은 교과서가 나오는게 아니라 전부 개발자들이 수기로 작성한 블로그들이 대부분이였다.

    이 문제는 코드를 짜다가 코드를 엎어야하는 상황을 야기한다. 왜냐하면 각자 코드 짜는 스타일들이 다 다르다보니 이 분의 코드와 저분의 코드가 그대로 연결되지 않기 때문이다.

    실제로 nodemodule을 가진 폴더만 5개까지 만들어졌었다 ㅋ

    그래서 하나하나 응용을 해야했다. 그대로 복붙이 안먹힘 ㅠㅠ

  2. Vue.js에서 Node.js api로 파라미터 보내기

    서버를 작동시키고 포스트맨으로 200이 출력 됐을때 사실 다 끝난 줄 알았다. 그런데 프론트에서 넘어오는 form 데이터들이 제대로 들어오지 않았다.

    뭐 예를 들어, 포스트맨으로 form-data로 넣으면 작동을 안하지만 raw에서 json 형식, x-www-form (뭔지 모름) 으로 넣으면 들어간다거나

    api 함수들에 sql 문들이 들어가는데 몇가지는 node.js의 특별한 문법으로 보인다.

 connection.query('SELECT * FROM user WHERE user_id = ? AND password = ?', [req.body.user_id, req.body.password], function(error, results, fields)

=> 다음과 같은 함수들 온전히 sql문은 아닌거 같은 특히 ?와 []로 인자를 넣는 것

3. 해결

1) mysql 연결 (나중에 사용할 성정들 포함)

(1) express

//express 모듈 불러오기
const express = require("express");

//express 사용
const app = express();

(2) Mysql 연결

var mysql = require('mysql');
var connection = mysql.createConnection({
    host: '', 
    port: '', 
    user: '', 
    password: '', 
    database: ''
});

connection.connect();

=> workbench에 있는 host와 hostname이 헤깔린다.
여기 host에는 port 옆에 있는 host를 써주면 된다. port와 둘을 연결 시켜서 주소를 생성하는셈

(3) Vue.js에서 던지는 파라미터를 body 라는 오브젝트 안에 담는다.

app.use(express.json());
app.use(express.urlencoded({ extended: true}));

=> 옛날 코드에서는 body-parser를 직접적으로 적용해주는데,

Express 4.16.0버전 부터 body-parser의 일부 기능이 익스프레스에 내장 body-parser 연결

(4) CORS 해결

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

=> API에 필수인 CORS를 해결하는 코드
=> 검색을 해보면 CORS allow all 또는 무시하는 법으로 검색이 되는데 이건 그 중 가장 직관적인 allow all하는 방법

(5) 임시 데이터 (왜 넣는지 모름 많은 예시 코드들에서 임시 데이터라는 이유로 넣음;)

var users = [
 { id: 1, name: "유저1" },
 { id: 2, name: "유저2" },
 { id: 3, name: "유저3" }
];

(6) mysql에서 테이블 불러오기

connection.query('SELECT * from 테이블명', function(err, rows, fields) {
  if (!err)
    console.log('The solution is: ', rows);
  else
    console.log('Error while performing Query.', err);
});

=> 연결이 됐는지 확인하기 가장 쉬운 방법인듯
=> connection은 mysql을 연결 시켰을때 사용된 변수이다.
=> sql문도 정확히 일반 sql문과 일치 ; 없는거 빼면

(7) config (맨 아래에 주로 씀, 한번 쓰면 신경 쓸 필요 없어서인듯)

app.set('port', process.env.PORT || 8888);
app.get('/', function(req, res){
  res.send('Hello World!');
});

=> 지금 프로젝트에서는 8000, 8080을 스프링이랑 장고가 차지하고 있기 때문에 8888로 설정

=> 지금까지 코드로 테이블을 온전히 가져올 수 있다.

2) Signup

=> Vue.js html에서 form으로 signup 함수 실행

=> actions에 있는 코드이다.
=> mapAction을 활용해 실행 시켰다.

signup({dispatch}, signupObj) {
        console.log('하이')
        console.log(signupObj)
        axios
            .post('http://localhost:8888/api/users/add', signupObj)
            .then(res => {
                console.log(res)
                // let user_id = res.data.user_id
                // let nickname = res.data.nickname
                // let password = res.data.password
                // let loginObj = {
                //     user_id: user_id,
                //     nickname: nickname,
                //     password: password
                // }
                // console.log(loginObj)
                console.log('회원가입 완료')
                router.push({ name: "Login" })
                // dispatch('login', loginObj)
            })
            .catch(() => {
            alert('다시 입력해주세요!')
        })
    },

=> 가장 먼저! 아무래도 회원가입, 로그인 폼을 전에 했던 프로젝트에서 복붙을 하다보니 email로 받았던 기능을 user_id로 바꾸는 등 변수들이 바뀌었다. 그런데 이걸 꼼꼼하게 체크하지 않았기 때문에 문제가 생기고 또 에러가 나오지 않기 때문에 찾아내기도 힘들었다.

=> 단, 이번에 또 경험했지만 맞왜틀(주로 오타) 같은 경우 혼자 고민해서는 10시간이 걸려도 못찾을 수 있다는 점이다. 그러나 다른 동료가 한번 확인해주면 10분만에 찾아낼수도 있다.

실제로 같이 프로젝트하는 팀원분이 이 문제를 정말 순식간에 발견하셨다.

=> 또한 에러의 특징에서 디버깅의 힌트를 찾아야한다는 점이다.
막무가내로 아 맞는데 왜그러지 보다는 에러의 특징을 잡고 그 뒤를 밟아야한다. 특히 정말 새벽에 오랫동안 고생한 에러 중 하나는

user_id, password, nickname 이 데이터로 들어오는데 user_id만 null이 찍히는 것이다. 분명 이 셋은 똑같은 형식의 코드를 거치는데.

여기서 user_id만을 쭉 추적해보았어야했다. 특히, 오타

=> 실제로 그 전 프로젝트에서 쓴 id가 눈을 시퍼렇게 뜨고 자리를 차지하고 있었다. 충격과 공포.

=> // 주석 처리한 데이터들은 원래 회원가입하면 자동으로 login 함수를 dispatch로 실행하면서 넘길 데이터였다. 그런데 이 코드를 보시고 코치님이 아주 깜짝 놀라셨다. password를 이렇게 프론트로 다시 던지는 경우는 절대 안된다는 것이다.

=> 현재 보안에 대한 공부도 차근 차근 이제 익숙해지니 시작해야겠다.

=> 또한 actions의 함수들에 쓰지 않더라도 {dispatch} 파라미터를 넣어주어야한다.

3) login

(세줄 signup과 동일)
=> Vue.js html에서 form으로 signup 함수 실행

=> actions에 있는 코드이다.
=> mapAction을 활용해 실행 시켰다.

app.post("/api/login/", (req, res) => {
    console.log('login')
    console.log(req)
    console.log(req.body)
    console.log(req.body.user_id)
    connection.query('SELECT * FROM user', function(err, rows) {
        if(err) throw err;
        console.log('res')
        connection.query('SELECT * FROM user WHERE user_id = ? AND password = ?', [req.body.user_id, req.body.password], function(error, results, fields) {

            console.log('The solution is: ', results);
            
            res.send({
                "code": 200,
                // "user_id": results[0].user_id,
                "success": "user login sucessfully"
            });
        })
    })
})

=> 가장 먼저 req 오브젝트가 잘 출력이 되지 않았다.
=> 알고보니 그 이유는 {dispatch} 파라미터를 명시하지 않았던거 쓰지 않더라도 넣어주자 (솔직히 이유는 모르겠음)

connection.query('SELECT * FROM user WHERE user_id = ? AND password = ?', [req.body.user_id, req.body.password], function(error, results, fields) {

            console.log('The solution is: ', results);
            
            res.send({
                "code": 200,
                // "user_id": results[0].user_id,
                "success": "user login sucessfully"
            });
        })

=> 가장 고생을 많이 시킨 부분
=> 특히 orm 같은 node.js의 특수 sql 문법이 설마설마 하다가 설마였다.
=> 위의 코드들이 sql 문들이 정확히 그대로 들어간걸 보고 여기도 당연히 sql문 그대로라고 생각했다.
=> 그래서 열심히 where user = ${user_id}게 작성
=> results가 빈값으로 나왔다 ... 젠장

=> 결국 해당 문법을 찾았고 성공할 수 있었다.
=> 가장 밑 부분 상태를 출력하는 부분 같은 경우
=> 처음에 Row어찌고로 한번 감싸져 있었기 때문에 [0]으로 까주고 key 값으로 출력해주었다.

=> 내가 혼자 했을때는 results에서 데이터가 시작된다는 생각을 못해 바로 user_id 변수를 만들어 때려 박았는데 안돼서 혹시 여기에는 내가 커스텀 못하나 하며 눈에 보이는 논리를 의심하기 시작했었다.

둘다 성공

=> 또 하나 느낀점은 흐름에 맞춰서 이건 맞겠지 판단하지 말고 하나하나 체크하며 뭐가 문제인지 디버깅을 해나가야한다는 것이다. 한줄한줄 input이 생기고 output이 생기는 코드들마다 출력을 해나가며 확인해야한다.

=> 온겸 코치님이 보여주신 디버깅 잊지말고 이대로 내가 할 수 있도록 하자!

아자!

profile
긍정적인 에너지를 가진 개발자, 이태성입니다.

0개의 댓글