Node.js | 로그인&회원가입 05

m1njae·2022년 2월 23일
0

로그인&회원가입

목록 보기
5/7
post-thumbnail

데이터 파일로 관리하기

UserStorage에 있는 로그인 데이터를 src폴더에 db폴더를 생성한 후, users.json파일로 옮겨준다.

{
    "id": ["minjae","rkdalswo1021", "mj991021"],
    "password": ["1234","12345","123456"],
    "name": ["민재", "강민재", "강민재2"]
}

따로 분리를 시켜주었으니 users.json파일에 접근을 해서 해당 데이터를 읽어올 수 있어야 하므로 파일 시스템을 불러와주어야 한다.

//in UserStorage

const fs = require("fs");

// 생략...

static  getUserInfo(id){
  return fs.readFile("./src/db/users.json", (error, data) =>{
    if (error) throw error;
    		const users = JSON.parse(data);
            const idx = users.id.indexOf(id);
            const usersKeys = Object.keys(users);
            const userInfo = usersKeys.reduce((newUser, info) => {
                newUser[info] = users[info][idx];
                return newUser;
            },{});
        
         return userInfo;
  });

다음과 같이 코드를 작성을 했으나, 로그를 찍어보았을 때, undefined이 출력되는 것을 확인할 수 있었다. 그 이유는 fs.readFile()의 콜백 함수는 반환을 하지만, fs.readFile()가 반환하는 값은 없기 때문이다. 그렇다면 어떻게 문제를 해결해야 할 수 있을까?

파일 DB로 로그인 구현

문제를 해결하기 위해서 promiseasync,await에 대해서 알아야한다. promise는 fetch API에서도 활용되어 있지만, 한번 더 짚고 넘어가려고 한다. promise는 주로 서버에서 받아온 데이터를 화면에 표시하기 위해 사용하며, 수행하는 동작이 끝남과 동시에 상태를 알려주기 때문에 비동기 처리에 효과적이다.

async는 함수 키워드 앞에 async 키워드를 위치시킨다. 함수 앞에 async를 붙이면 해당 함수는 항상 promise를 반환한다.async가 붙은 함수는 반드시 promise를 반환하고, promise가 아닌 것은 promise로 감싸서 반환해준다.

awaitasync 함수 안에서만 동작한다. 자바스크립트는 await 키워드를 만나면 promise가 처리될 때까지 기다리게 되며 결과는 그 이후 반환된다.

fs.readFile() 자체에서 promise를 제공하고 있기 때문에 이러한 부분들을 고려하여 작업해주었다.

//in UserStorage.js

const fs = require("fs").promises; // promise를 반환할 수 있도록

class UserStorage{
    
    static #getUserInfo(data, id){
            const users = JSON.parse(data);
            const idx = users.id.indexOf(id);
            const usersKeys = Object.keys(users); 
            const userInfo = usersKeys.reduce((newUser, info) => {
                newUser[info] = users[info][idx];
                return newUser;
            },{});
        
         return userInfo;
    }
    
    // 생략..
    
    static getUsersInfo(id){
        //const users = this.#users;
        return fs.readFile("./src/db/users.json")
          .then((data) => {
            return this.#getUserInfo(data, id);
          })
          .catch(console.error);
    }

getUserInfo가 값을 반환하기 전까지는 그 다음 과정이 실행이 되서는 안된다. asyncawait 함수를 활용해서 설정해주었다.

//in home.ctrl.js
const process = {
    	login: async function (request, response){ // function 앞에 async 키워드 부여
        const user = new User(request.body);
        const res = await user.login(); // await
        return response.json(res);
    },
  	
  	// 생략..
}

//in User.js

class User {
    constructor(body){
        this.body = body;
    }

   async login() { // async 키워드 부여
        const client = this.body;
        const { id, password } = await UserStorage.getUsersInfo(client.id); // await
        
        if (id) {
            if (id === client.id && password === client.password){
                return {success: true};
            }
            return {success: false, message: "비밀번호가 틀렸습니다."};
        }
        return {success: false, message: "등록되지 않은 아이디입니다."};
}

파일 DB로 회원가입 구현

로그인 구현과 비슷한 방식으로 구현해주었다.

// in UserStorage.js
const fs = require("fs").promises;

class UserStorage{
  	// 생략..  
  
    static #getUsers(data, isAll, fields){
        const users = JSON.parse(data);
        if (isAll) return users;
        const newUsers = fields.reduce((newUsers, field) => {
            if (users.hasOwnProperty(field)){
                newUsers[field] = users[field];
            }
            return newUsers; 
        }, {});
        return newUsers;
    }

    // 은닉화된 데이터를 가져오도록 하는 메소드
    static getUsers(isAll, ...fields) {
        return fs.readFile("./src/db/users.json")
          .then((data) => {
            return this.#getUsers(data, isAll, fields);
          })
          .catch(console.error);
        //const users = this.#users;
        
    }

    static async save(userInfo){
        const users = await this.getUsers(true);
        if (users.id.includes(userInfo.id)){
            throw "이미 존재하는 아이디입니다.";
        }
            users.id.push(userInfo.id);
            users.password.push(userInfo.password);
            users.name.push(userInfo.name);
            fs.writeFile("./src/db/users.json", JSON.stringify(users));
            return { success: true};
    }
}
//in home.ctrl.js

const process = {
	// 생략..
  
    register: async function (request, response){
        const user = new User(request.body);
        const res = await user.register();
        return response.json(res);
    }
}


// in User.js
class User {
    constructor(body){
        this.body = body;
    }
	
  	// 생략..
  
    async register() {
        const client = this.body;
        try{
        const response = await UserStorage.save(client);
        return response;
        } catch(error){
            return { success: false, message: error};
        }
    }
}

아이디가 kangminjae이고, 이름은 강민재3, 비밀번호가 1021인 정보로 회원가입 했을 때, users.json파일에 정보가 잘 들어오는 것을 확인할 수 있었다.

느낀 점

학습을 진행하면서 초반에 비해 이해가 되지 않는 부분들이 많아서 계속해서 영상을 돌려보고 찾아보면서 학습하고 있다. 비동기적인 처리도 단어를 이론적으로 어느 정도 알고 있었다. 코드에서 활용되는 것을 경험하면서 신기하기했지만 아직 와닿는 느낌은 없었다..ㅠ 어렵지만 복습하면서 계속 부딪혀 보아야겠다. 따라 하는 것도 어렵고, 공부해야할 게 산더미다!

https://github.com/m1njae/login-lecture

참고

[Node.js] 백엔드 맛보기
Node.js | Promise 작동 원리
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

profile
할 수 있는 것부터 차근차근, 항해자의 공부 기록공간

0개의 댓글