๐ŸŒ– The Art of React part2

hwakyungChoiยท2021๋…„ 1์›” 2์ผ
0

๐ŸŽ„ ํ”„๋กœ์ ํŠธ ์ •๋ฆฌ

  • ๋ฐ์ดํ„ฐ ์Šคํ‚ค๋งˆ๊ฐ€ ๊ณ ์ •์ ์ด๋ฉฐ ํ™•์žฅ์„ฑ์ด ์—†๋Š” ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ ์ž mongoDB๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋๋‹ค.
  • ๋ฌธ์„œ ์ง€ํ–ฅ์  NoSQL๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์ด๋ฉฐ Node.js ํ™˜๊ฒฝ์—์„œ๋Š” mongoDB ๊ธฐ๋ฐ˜ ODM(Object Data Modeling) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ mongoose์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค.
  • Node.js์—์„œ import/export๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” esm ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • monogoose์—์„œ ์Šคํ‚ค๋งˆ์™€ ๋ชจ๋ธ์ด๋ผ๋Š” ๊ฐœ๋…์ด ์žˆ๋Š”๋ฐ ์Šคํ‚ค๋งˆ๋Š” ์ปฌ๋ ‰์…˜์— ๋“ค์–ด๊ฐ€๋Š” ๋ฌธ์„œ ๋‚ด๋ถ€์˜ ๊ฐ ํ•„๋“œ๊ฐ€ ์–ด๋–ค ํ˜•์‹์œผ๋กœ ๋˜์–ด ์žˆ์–ด ์žˆ๋Š”์ง€ ์ •์˜ ํ•˜๋Š” ๊ฐ์ฒด์ด๋ฉฐ ๋ชจ๋ธ์€ ์ธ์Šคํ„ด์Šค๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‹ค์ œ๋กœ ์ž‘์—…ํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด์ด๋‹ค
  • monogoDB compass๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ์กฐํšŒ/์ˆ˜์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” GUI ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.
  • Joi ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฐ์ฒด์˜ ๊ฐ ๊ฐ’์„ ๊ฒ€์ฆ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.
  • lean()ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ JSON ํ˜•ํƒœ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • REST API์— mongoDB๋ฅผ ์—ฐ๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ธฐ๋Šฅ๊นŒ์ง€ ๊ตฌํ˜„ํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๐Ÿ”ฅ ์ฝ”๋“œ

// post/index.js
import Router from 'koa-router';
import * as postsCtrl from './posts.ctrl';

const posts = new Router();

posts.get('/', postsCtrl.list);
posts.post('/', postsCtrl.write);

const post = new Router(); // /api/posts/:id
post.get('/', postsCtrl.read);
post.delete('/', postsCtrl.remove);
post.patch('/', postsCtrl.update);

posts.use('/:id', postsCtrl.checkObjectId, post.routes());

export default posts;

// posts.ctrl.js
import Post from "../../models/post"
import mongoose from "mongoose";
import Joi from "joi"

const { ObjectId } = mongoose.Types;

export const checkObjectId = (ctx, next) => {
    const { id } = ctx.params;

    if (!ObjectId.isValid(id)) {
        ctx.status = 400;
        return;
    }
    return next();
}

export const write = async ctx => {
    // ๊ฐ์ฒด ๊ฒ€์ฆ์„ ์ˆ˜์›”ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” joi๊ฐ€ ์žˆ์Œ
    const schema = Joi.object().keys({
        title: Joi.string().required(),
        body: Joi.string().required(),
        tags: Joi.array().items(Joi.string()).required()
    })
    // const result = Joi.validate(body, schema);
    // const validation = schema.validate(body);
    const result = schema.validate(ctx.request.body);

    if (result.error) {
        ctx.status = 400;
        ctx.body = result.error;
        return;
    }

    const { title, body, tags } = ctx.request.body;
    const post = new Post({ title, body, tags });
    try {
        await post.save();
        ctx.body = post;
    } catch (e) {
        ctx.throw(500, e)
    }
};


export const list = async ctx => {
    const page = parseInt(ctx.query.page || "1", 10);
    if (page < 1) {
        ctx.status = 400;
        return;
    }
    try {
        //lean ํ•จ์ˆ˜๋Š” ์ฒ˜์œผใ…๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ JSON ํ˜•ํƒœ๋กœ ์กฐํšŒ ๊ฐ€๋Šฅ
        const posts = await Post.find()
            .sort({ _id: -1 })
            .limit(10)
            .skip((page - 1) * 10)
            .lean()
            .exec();
        const postCount = await Post.countDocuments().exec();
        ctx.set('Last-Page', Math.ceil(postCount / 10));

        ctx.body = posts.map(post => ({
            ...post, body: post.body.length < 200 ? post.body : `${post.body.slice(0, 200)}...`
        }))
    } catch (e) {
        ctx.throw(500, e)
    }
};

export const read = async ctx => {
    const { id } = ctx.params;
    try {
        const post = await Post.findById(id).exec();
        console.log(id)
        if (!post) {
            ctx.status = 404;
            return;
        }
        ctx.body = post
    } catch (e) {
        ctx.throw(500, e)
    }
};

export const remove = async ctx => {
    const { id } = ctx.params;
    try {
        await Post.findByIdAndRemove(id).exec();
        ctx.status = 204;
    } catch (e) {
        ctx.throw(500, e)
    }
};

export const update = async ctx => {
    const { id } = ctx.params;
    const schema = Joi.object().keys({
        title: Joi.string(),
        body: Joi.string(),
        tags: Joi.array().items(Joi.string())
    })

    const result = schema.validate(ctx.request.body);
    //๊ฒ€์ฆํ•˜๊ณ  ๋‚˜์„œ ๊ฒ€์ฆ ์‹คํŒจ์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ
    if (result.error) {
        ctx.status = 400;
        ctx.body = result.error;
        return;
    }


    try {
        const post = await Post.findByIdAndUpdate(id, ctx.request.body, {
            new: true
        }).exec();
        if (!post) {
            ctx.status = 404;
            return;
        }
        ctx.body = post
    } catch (e) {
        ctx.throw(500, e)
    }
};

0๊ฐœ์˜ ๋Œ“๊ธ€