๐ŸŽฏ API์— JWT๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ ์ ์šฉ์‹œํ‚ค๊ณ , try/catch๋ฅผ ํ†ตํ•ด ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“™ Today I Learned

์ข‹์•„์š” API ์„ค๊ณ„


์ˆ˜์ •ํ•œ ๋ถ€๋ถ„์€ ์ฃผํ™ฉ์ƒ‰ ๊ธ€์”จ๋กœ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์ข‹์•„์š” ์ถ”๊ฐ€

  • Method : POST

  • URL : /likes/:bookId

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Response Body : x


์ข‹์•„์š” ์ทจ์†Œ

  • Method : DELETE

  • URL : /likes/:bookId

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Response Body : x




์ฃผ๋ฌธ(๊ฒฐ์ œ) API ์„ค๊ณ„

์ฃผ๋ฌธํ•˜๊ธฐ

  • Method : POST

  • URL : /orders

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Request Body

{
  "items": [ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋„์„œ id, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋„์„œ id, ...],
  "delivery" : {
    	"address" : "์ฃผ์†Œ",
    	"receiver" : "์ด๋ฆ„",
    	"contact" : "์ „ํ™”๋ฒˆํ˜ธ"
  },
  "totalQuantity" : ์ด ์ˆ˜๋Ÿ‰,
  "totalPrice" : ์ด ๊ธˆ์•ก,
  "firstbookTitle" : "๋Œ€ํ‘œ ๋„์„œ ์ œ๋ชฉ"
}
  • Response Body : x

์ฃผ๋ฌธ ๋ชฉ๋ก ์กฐํšŒ

  • Method : GET

  • URL : /orders

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Response Body :

[
  {
    "order_id" : ์ฃผ๋ฌธ id,
  	"created_at" : "์ฃผ๋ฌธ์ผ์ž",
    "address" : "์ฃผ์†Œ",
    "receiver" : "์ด๋ฆ„",
    "contact" : "์ „ํ™”๋ฒˆํ˜ธ",
  	"book_title" : "๋Œ€ํ‘œ ์ฑ… ์ œ๋ชฉ",
    "total_quantity" : ์ด ์ˆ˜๋Ÿ‰,
  	"total_price" : ๊ฒฐ์ œ ๊ธˆ์•ก,

  },
  {
    "order_id" : ์ฃผ๋ฌธ id,
  	"created_at" : "์ฃผ๋ฌธ์ผ์ž",
    "address" : "์ฃผ์†Œ",
    "receiver" : "์ด๋ฆ„",
    "contact" : "์ „ํ™”๋ฒˆํ˜ธ",
  	"book_title" : "๋Œ€ํ‘œ ์ฑ… ์ œ๋ชฉ",
  	"total_quantity" : ์ด ์ˆ˜๋Ÿ‰,
    "total_price" : ๊ฒฐ์ œ ๊ธˆ์•ก,
  },
  ...
]

์ฃผ๋ฌธ ์ƒ์„ธ ์กฐํšŒ

  • Method : GET

  • URL : /orders/:id

  • HTTP Status Code : 200 Ok

  • Request Body : x

  • Response Body :

[
  {
    "book_id" : ๋„์„œ id,
    "title" : "๋„์„œ ์ œ๋ชฉ",
    "author" : "์ž‘๊ฐ€",
    "price" : ๊ฐ€๊ฒฉ,
    "quantity" : ์ˆ˜๋Ÿ‰
  },
  {
    "book_id" : ๋„์„œ id,
    "title" : "๋„์„œ ์ œ๋ชฉ",
    "author" : "์ž‘๊ฐ€",
    "price" : ๊ฐ€๊ฒฉ,
    "quantity" : ์ˆ˜๋Ÿ‰
  },
  ...
]



์žฅ๋ฐ”๊ตฌ๋‹ˆ API ์„ค๊ณ„

์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ

  • Method : POST

  • URL : /carts

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Request Body

  {
    "bookId" : ๋„์„œ id,
    "quantity" : ์ˆ˜๋Ÿ‰,
  }
  • Response Body : x

์žฅ๋ฐ”๊ตฌ๋‹ˆ ์กฐํšŒ / ์„ ํƒ ์ƒํ’ˆ ์กฐํšŒ(์ฃผ๋ฌธ์„œ ์ž‘์„ฑ)

  • Method : GET

  • URL : /carts

  • HTTP Status Code : 200 Ok

  • Request Headers : 'Authorization' : JWT Token

  • Request Body :

{
   "selected" : [cartItemId, cartItemId ...]
}
  • Response Body
 [
  { 
    "id" : ์žฅ๋ฐ”๊ตฌ๋‹ˆ id,
    "bookId" : ๋„์„œ id,
    "title" : "๋„์„œ ์ œ๋ชฉ",
    "summary" : "์š”์•ฝ ์„ค๋ช…",
    "quantity" : ์ˆ˜๋Ÿ‰,
    "price" : ๊ฐ€๊ฒฉ
  },
  {
    "id" : ์žฅ๋ฐ”๊ตฌ๋‹ˆ id,
    "bookId" : ๋„์„œ id,
    "title" : "๋„์„œ ์ œ๋ชฉ",
    "summary" : "์š”์•ฝ ์„ค๋ช…",
    "quantity" : ์ˆ˜๋Ÿ‰,
    "price" : ๊ฐ€๊ฒฉ
  },
 ]

์žฅ๋ฐ”๊ตฌ๋‹ˆ ์‚ญ์ œ

  • Method : DELETE

  • URL : /carts/:cartItemId

  • HTTP Status Code : 200 Ok

  • Request Body : x

  • Response Body : x




LikeController.js

const jwt = require('jsonwebtoken');
const conn = require('../mariadb');
const { StatusCodes } = require('http-status-codes');
const dotenv = require('dotenv');
dotenv.config();

const addLike = (req, res) => {
  const likedBookId = req.params.id;

  let authorization = ensureAuthorization(req, res);

  if (authorization instanceof jwt.TokenExpiredError) {
    return res.status(StatusCodes.UNAUTHORIZED).json({
      message: '๋กœ๊ทธ์ธ ์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.',
    });
  } else if (authorization instanceof jwt.JsonWebTokenError) {
    return res.status(StatusCodes.BAD_REQUEST).json({
      message: '์ž˜๋ชป๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค.',
    });
  } else {
    const sql = 'INSERT INTO likes (user_id, liked_book_id) VALUES (?, ?)';
    const values = [authorization.id, likedBookId];
    conn.query(sql, values, (err, result) => {
      if (err) {
        console.log(err);
        return res.status(StatusCodes.BAD_REQUEST).end();
      }

      return res.status(StatusCodes.CREATED).json(result);
    });
  }
};

const removeLike = (req, res) => {
  const likedBookId = req.params.id;

  let authorization = ensureAuthorization(req, res);

  if (authorization instanceof jwt.TokenExpiredError) {
    return res.status(StatusCodes.UNAUTHORIZED).json({
      message: '๋กœ๊ทธ์ธ ์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.',
    });
  } else if (authorization instanceof jwt.JsonWebTokenError) {
    return res.status(StatusCodes.BAD_REQUEST).json({
      message: '์ž˜๋ชป๋œ ํ† ํฐ์ž…๋‹ˆ๋‹ค.',
    });
  } else {
    const sql = 'DELETE FROM likes WHERE user_id =? AND liked_book_id = ?';
    const values = [authorization.id, likedBookId];
    conn.query(sql, values, (err, result) => {
      if (err) {
        console.log(err);
        return res.status(StatusCodes.BAD_REQUEST).end();
      }

      return res.status(StatusCodes.OK).json(result);
    });
  }
};

function ensureAuthorization(req, res) {
  try {
    let receivedJwt = req.headers['authorization'];
    let decodedJwt = jwt.verify(receivedJwt, process.env.PRIVATE_KEY);

    return decodedJwt;
  } catch (error) {
    return error;
  }
}

module.exports = {
  addLike,
  removeLike,
};
  • ensureAuthorization : ์š”์ฒญ headers์—์„œ authorization ๊ฐ’์„ ๊ฐ€์ ธ์™€ JWT๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

    • JWT๊ฐ€ ์œ ํšจํ•˜๋ฉด decodeJwt๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    • JWT๊ฐ€ ๋งŒ๋ฃŒ๋˜์—ˆ๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ์—๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

      • ๋งŒ๋ฃŒ๋œ ํ† ํฐ์ด๋ฉด 401 UNAUTHORIZED ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

      • ์ž˜๋ชป๋œ ํ† ํฐ์ด๋ฉด 400 BAD REQUEST ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.




โœ๏ธ ํ•œ ์ค„ ํšŒ๊ณ 

JWT ์ธ์ฆ์„ ํ•˜๋ฉด์„œ token ๋งŒ๋ฃŒ๋  ๋•Œ๋งˆ๋‹ค ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ ๋ณต๋ถ™ํ•˜๋Š” ๊ฒŒ ๋ฒˆ๊ฑฐ๋กœ์› ์Šต๋‹ˆ๋‹ค.๐Ÿ˜‚ ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋“œ๋ฅผ ์งค์ˆ˜๋ก ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ๋” ์ฒด๊ณ„์ ์œผ๋กœ ํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ๋А๊ผˆ์Šต๋‹ˆ๋‹ค.

profile
๐ŸŒฑ๊ฐœ๋ฐœ ๊ธฐ๋ก์žฅ

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