Web Dev/5. Projects

[toy blog service] Next.js의 API와 json

hYhY1234 2021. 4. 19. 22:06
728x90

Next.js에서는 API 관련 기능을 제공한다. 

 

여기를 보면 이런식으로 구성을 해서 /api/* 로 매핑이 된다. 얘들은 서버사이드에서만 번들링이 된다. 

 

나는 여기서 공부를 위해서 여러 endpoint를 만들어봤는데, 아래는 /api/[username]/index 를 처리하는 파일은 아래와 같이 작성했다. 

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
import { selectData, insertData } from "../../../../utils/common";

// http://localhost:3000/api/articles/hayoung
// let r1 = await fetch("http://localhost:3000/api/articles/hayoung", { method: 'POST', body: JSON.stringify({ title: "title!!!", contents: "teststststs", viewCount: 1 }) })
export default async (req: NextApiRequest, res: NextApiResponse) => {
  const username = req.query.username;
  if (req.method === "GET") {
    // get every article by this user
    const selectResult = await selectData("articles", {
      author: username as string,
    });
    res.status(200).json({ message: selectResult });
    return;
  }

  if (req.method === "POST") {
    // create a new article by this use
    // const reqData = JSON.parse(req.body);
    const reqData = JSON.parse(req.body);
    const createdData = await insertData("articles", {
      ...reqData,
      viewCount: "1",
      author: username,
    });

    if (createdData.length > 0) {
      res.setPreviewData(createdData[0], { maxAge: 10 });
      res.status(200).json({ message: createdData[0] });
    } else {
      res.status(200).json({ message: "something went wrong" });
    }
    return;
  }

  res.status(500).json({
    message:
      "Sorry, articles/username/articleId api only accepts GET or POST method",
  });
};

 

get, post 관련 처리를 위와 같이 쉽게 할 수 있다. 

 

 

 

Json 관련 처리

DB까지 달고 하다보면 공부범위가 너무 광범위 해지는 것같아 간단하게 fs 모듈로 json 데이터를 읽고 쓰는 방식으로 db를 흉내 내보았다. 

const selectData = async (
  keyName: string,
  filterKey?: filterKeyForUsers | filterKeyForArticles
) => {
  const db = await openJsonFile();

  if (keyName === "intro") {
    return db[keyName];
  }

  if (keyName === "users") {
    if (!filterKey) {
      return db[keyName];
    }

    if (!instanceOfFilterDataForArticles(filterKey)) {
      const result = [];
      db[keyName].forEach((row: UserType) => {
        if (row.userId === filterKey.userId) {
          result.push(row);
        }
      });

      return result;
    }
  }

  if (keyName === "articles") {
    if (!filterKey) {
      let result = [];
      for (const [author, articles] of Object.entries(db[keyName])) {
        if (instanceOfArticleList(articles)) {
          result = [...result, ...articles];
        }
      }
      return result;
    }

    if (
      instanceOfFilterDataForArticles(filterKey) &&
      db[keyName][filterKey.author] &&
      !filterKey.articleId
    ) {
      const result = [];

      db[keyName][filterKey.author].forEach((row: ArticleType) => {
        result.push(row);
      });
      return result;
    }

    if (
      instanceOfFilterDataForArticles(filterKey) &&
      db[keyName][filterKey.author] &&
      filterKey.articleId
    ) {
      const result = [];
      db[keyName][filterKey.author].forEach((row: ArticleType) => {
        if (row.articleId === filterKey.articleId) {
          result.push(row);
        }
      });
      return result;
    }
  }

  return [];
};

const insertData = async (keyName: string, data: UserType | ArticleType) => {
  const db = await openJsonFile();
  if (keyName === "users" && !instanceOfArticle(data)) {
    db[keyName].push(data);
    await writeJsonFile(db);
    return [data];
  }

  if (keyName === "articles" && instanceOfArticle(data)) {
    if (!db[keyName][data.author]) {
      db[keyName][data.author] = [];
    }
    // calc ArticleID
    let articleId =
      db[keyName][data.author].length === 0
        ? 1
        : +db[keyName][data.author][db[keyName][data.author].length - 1]
            .articleId + 1;
    data.articleId = "" + articleId;

    if (!db[keyName][data.author]) {
      db[keyName][data.author] = [];
    }

    db[keyName][data.author].push(data);
    await writeJsonFile(db);
    return [data];
  }

  return [];
};

const updateArticle = async (
  username: string,
  articleId: string,
  data: { title: string; contents: string }
) => {
  const db = await openJsonFile();
  const result = [];
  try {
    db["articles"][username].forEach((row: ArticleType, index: number) => {
      if (row.articleId === articleId) {
        db["articles"][username][index]["title"] = data.title;
        db["articles"][username][index]["contents"] = data.contents;
        result.push(db["articles"][username][index]);
      }
    });
    await writeJsonFile(db);
    return result;
  } catch (err) {
    console.log(err);
    return [];
  }
};

 

내가 실제로 작성했던 코드는 위와 같다. 

 

아래는 JSON데이터이다. 

이를 보면 각 api에서 원래 db처리를 하는 곳에 insertData와 같은 json 처리 함수를 사용했다.

 

 

후기

json으로 직접 구현하면서 using type predicates 같은 개념도 다루고, JavaScript 자체를 좀 빡세게 본것 같다. API 기능자체는 엄청 편리하게 제공해서 필요한 경우에 요긴하게 사용할 것 같다.