✅ API 구조 만들어보쟈

  • src/api/auth/auth.ctrl.js 디렉터리와 파일 만들기
export const register = async ctx => {
    // 회원가입
};
export const login = async ctx => {
    // 로그인
};
export const check = async ctx => {
    // 로그인 상태 확인
};
export const logout = async ctx => {
    // 로그아웃
};
  • src/api/auth/index.js 파일 생성해 auth 라우터 생성
import Router from 'koa-router';
import * as authCtrl from './auth.ctrl.js'

const auth = new Router();

auth.post('/register', authCtrl.register);
auth.post('/login', authCtrl.login);
auth.get('/check', authCtrl.check);
auth.post('/logout', authCtrl.logout);

export default auth;
  • 마지막으로 api폴더 index.js에서 api 라우터 적용해주기
// src/api/index.js
...
import auth from './auth/index.js'
...
api.use('/posts', posts.routes());
api.use('/auth', auth.routes());
...

✅ 회원가입 구현하기

// src/api/auth/auth.ctrl.js
import Joi from 'joi';
import User from '../../models/user.js'

/*
    POST /api/auth/register
    {
        username : '',
        password : ''
    }
*/
export const register = async ctx => {
    // joi로 request body 검증
    const schema = Joi.object().keys({
        username : Joi.string().alphanum().min(3).max(20).required(),
        password : Joi.string().required(),
    });
    const result = schema.validate(ctx.request.body);
    if(result.error) {
        ctx.status = 400;
        ctx.body = result.error;
        return;
    }

    const {username, password} = ctx.request.body;
    try {
        // 🌟 username 중복을 피하기 위해 존재 여부 확인
        const exists = await User.findByUsername(username);
        if(exists) {
            ctx.status = 409 // Conflict
            return;
        }

        const user = new User({
            username,
        });
        // 🌟 setPassword 인스턴스 함수로 비밀번호 설정
        await user.setPassword(password); 
        await user.save(); // 데이터베이스에 저장

        // 응답할 데이터에서 hashedPassword 필드 제거
        const data = user.toJSON();
        delete data.hashedPassword;
        ctx.body = data; 
    } catch (e) {
        ctx.throw(500, e);
    }
};
  • setPassword 처럼 스태틱, 인스턴스 함수 작업들을 API 내부에서 구현해도 상관 없지만,
  • 이처럼 메서드로 만들어 사용하면 가독성과 유지보수성이 높아짐
  • 마지막 hashPassword는 응답되지 않도록 제거해주었는데, 자주 사용되는 작업이므로 인스턴스 함수로 따로 만들어두쟈
// src/models/user.js
UserSchema.methods.serialize = function() {
    const data = this.toJSON();
    delete data.hashedPassword;
    return data;
}
  • 기존 코드도 대체
// src/api/auth/auth.ctrl.js
...
export const register = async ctx => {
    ...
        const user = new User({
            username,
        });
        await user.setPassword(password); 
        await user.save();
        ctx.body = user.serialize(); 
    } catch (e) {
        ctx.throw(500, e);
    }
};
...
  • postman으로 Request Body를 담아 POST 요청을 해보쟈

✅ 로그인 구현하기

// src/api/auth/auth.ctrl.js
/*
    POST /api/auth/login
    {
        username : '',
        password : ''
    }
*/
export const login = async ctx => {
    const {username, password} = ctx.request.body;

    // 🌟 username, password가 없으면 에러 처리
    if(!username || !password) {
        ctx.status = 401; // Unauthorized
        return;
    }

    try {
        const user = await User.findByUsername(username);
        // 🌟 계정이 존재하지 않으면 에러처리
        if(!user) {
            ctx.status = 401;
            return;
        }
        // 🌟 계정이 유효하면 비밀번호 검사해서 성공시 계정 정보 응답
        const valid = await user.checkPassword(password);
        if(!valid) {
            ctx.status = 401;
            return;
        }
        ctx.body = user.serialize();
    } catch (e) {
        ctx.throw(500, e)
    }
}
  • postman으로 Request Body를 담아 POST 요청을 해보쟈
profile
🥳믓진 개발자가 되겠어요🥳

1개의 댓글

comment-user-thumbnail
2023년 7월 21일

정말 유익한 정보를 얻었어요. 간결하게 설명된 API 구성과 회원가입, 로그인 구현 과정이 인상 깊었습니다. 이런 좋은 내용 공유해주셔서 감사합니다!

답글 달기
Powered by GraphCDN, the GraphQL CDN