Wordle Maker Project 7일차

PROLCY·2022년 11월 7일
0

Wordle-Maker-Project

목록 보기
7/31
post-custom-banner

오늘은 11월 7일 7일차이다.

목표

  • sequelize 모델 구성
  • API 구성

진행

먼저 sequelize를 mysql과 연동하기 위해 모델들을 구성했다. 그다음 maker 모델과 url 모델을 1대1로, url 모델과 solver 모델을 1대N으로 연결해줬다.
API는 오늘은 일단 makerPage 부분만 진행했다. 첫 번째는 POST /make/duplicated로, 닉네임 중복 검증이다. db에서 해당 닉네임을 가지는 로우를 찾아낸다. 닉네임 중복 검증이 끝나고 단어를 입력하면 POST /make/register 요청을 보낸다.

코드

const Sequelize = require('sequelize');

module.exports = class Maker extends Sequelize.Model {
    static init(sequelize) {
        return super.init({
            nickname: {
                type: Sequelize.STRING(20),
                allowNull: false,
                unique: true,
            },
            url: {
                type: Sequelize.STRING(200),
                allowNull: true,
            },
            created_at: {
                type: Sequelize.DATE,
                allowNull: false,
                defaultValue: Sequelize.NOW,
            },
        }, {
            sequelize,
            timestamps: false,
            underscored: false,
            modelName: 'Maker',
            tableName: 'makers',
            paranoid: false,
            charset: 'utf8',
            collate: 'utf8_general_ci',
        });
    }
    static associate(db) {
        db.Maker.hasOne(db.Url, { foreignKey: 'maker', sourceKey: 'id' });
    }
};

maker 모델이다. hasOne을 통해 url 모델과 1대1로 연결해줬다.

const Sequelize = require('sequelize');

module.exports = class Url extends Sequelize.Model {
    static init(sequelize) {
        return super.init({
            url: {
                type: Sequelize.STRING(200),
                allowNull: false,
            },
            correct_word: {
                type: Sequelize.STRING(10),
                allowNull: false,
            },
            created_at: {
                type: Sequelize.DATE,
                allowNull: false,
                defaultValue: Sequelize.NOW,
            },
        }, {
            sequelize,
            timestamps: false,
            underscored: false,
            modelName: 'Url',
            tableName: 'urls',
            paranoid: false,
            charset: 'utf8',
            collate: 'utf8_general_ci',
        });
    }
    static associate(db) {
        db.Url.belongsTo(db.Maker, { foreignKey: 'maker', targetKey: 'id' });
        db.Url.hasMany(db.Solver, { foreignKey: 'url', sourceKey: 'id' });
    }
};

url 모델이다. belongsTo를 통해 maker 모델과 묶어줬고, hasMany를 통해 solver 모델과 1대N 관계로 묶어줬다.

const Sequelize = require('sequelize');

module.exports = class Solver extends Sequelize.Model {
    static init(sequelize) {
        return super.init({
            nickname: {
                type: Sequelize.STRING(20),
                allowNull: false,
            },
            word_list: {
                type: Sequelize.STRING(200),
                allowNull: true,
            },
            created_at: {
                type: Sequelize.DATE,
                allowNull: false,
                defaultValue: Sequelize.NOW,
            },
        }, {
            sequelize,
            timestamps: false,
            underscored: false,
            modelName: 'Solver',
            tableName: 'solvers',
            paranoid: false,
            charset: 'utf8',
            collate: 'utf8_general_ci',
        });
    }
    static associate(db) {
        db.Solver.belongsTo(db.Url, { foreignKey: 'url', targetKey: 'id' });
    }
};

solver 모델이다. belongsTo를 통해 url 모델과 묶어줬다.

const Sequelize = require('sequelize');
const Maker = require('./maker');
const Url = require('./url');
const Solver = require('./solver');

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};

const sequelize = new Sequelize(config.database, config.username, config.password, config);

db.sequelize = sequelize;

db.Maker = Maker;
db.Url = Url;
db.Solver = Solver;

Maker.init(sequelize);
Url.init(sequelize);
Solver.init(sequelize);

Maker.associate(db);
Url.associate(db);
Solver.associate(db);

module.exports = db;

models 폴더의 index.js 파일이다.

client.post('/make/duplicated', { nickname: nickname })
.then( res => {
    if ( res.data === 'duplicated') {
        nickname = '';
        setMessage('It already exists!');
        setWordState('not-word');
        setTimeout(() => {setWordState(''); setMessage(null);}, 500);
        return;
    }
    else {
        submitNickname = true;

        for( let i = 0 ; i < wordMaxLen ; i++ ) {
            word[i].state = 'correct';
        }
        setWordList({
            ...wordList,
            word,
        });
        
        setTimeout(() => {
            
            setWord([]);
            setWordList({
                word,
            });
            setMessage('Enter your word!')
        }, 2000);
    }
});

POST /make/duplicated 요청 부분이다. 요청을 보내 중복이라는 응답을 받으면 message를 출력하며 애니메이션을 진행시킨다. 아니라면 애니메이션을 진행시키고, 단어를 입력하는 보드로 넘어간다.

client.post('/make/register', { 
    nickname: nickname, 
    correct_word: correct_word, 
})
    .then( res => {
        console.log(res);
    })

setTimeout(() => {
    setMessage('Your Wordle was made!');
}, 2000);

// 만든 문제 링크 띄우기(모달 or 링크 복사 div)

POST /make/register 요청 부분이다. nickname과 correct_word를 담은 객체를 요청으로 보내고 서버에서 등록하도록 한다.

const express = require('express');
const axios = require('axios');
const { Maker, Url } = require('../models');

const router = express.Router();

router.post('/duplicated', async (req, res) => {
    try {
        const nickname = req.body.nickname;
        const maker = await Maker.findOne({
            where: {
                nickname: nickname
            }
        });
        if( maker == null )
            res.send('not-duplicated');
        else
            res.send("duplicated");
    } catch (error) {
        console.error(error);
    }
})

router.post('/register', async (req, res) => {
    try {
        const nickname = req.body.nickname;
        const correct_word = req.body.correct_word;
        console.log(nickname, correct_word);
        const URL = 'http://localhost:3000/' + nickname + '/' + correct_word;

        const maker = await Maker.create({
            nickname: nickname,
            url: URL,
        });
        const url = await Url.create({
            url: URL,
            correct_word: correct_word,
            maker: maker.id,
        });
        res.send({
            url: URL,
        });
    } catch (error) {
        console.error(error);
    }
});

module.exports = router;

서버의 make 라우터 부분이다. 중복 여부는 데이터베이스에서 해당 닉네임을 찾아검증한다. 등록은 URL을 생성한 후, maker 모델에 닉네임과 url을 등록, url 모델에 url과 correct_word를 등록하고, maker 칼럼에 방금 만든 maker 모델의 id를 등록한다. 이후 url을 응답으로 보낸다.

HARRY 라는 닉네임을 입력했다.

단어 입력 창으로 넘어가서 BEGIN 단어를 등록했다.

DB에 잘 등록되어 있는 모습이다.

보충할 것

  • sql query 지식
  • sequelize 모델 구성 방법

내일 할 것

  • solverPage API 구성
  • makerPage에서 url 렌더링 요소 생성(시간이 되면)

마무리

오늘은 시간이 간만에 좀 나서 진행을 많이 한 것 같다. 모델간의 관계를 정의해서 db 구성하는 것은 처음인데, 많이 신기했고 재밌었다. 그래도 아직 sql에 관해서 쿼리도 잘 모르고, 그에 대응되는 sequelize 구문도 찾아보고 하는 수준이라 많이 부족한 것 같다. 더 노력해야지.

post-custom-banner

0개의 댓글