본문 바로가기
웹개발/Next

Next.js에서 api를 쓰는 이유

by oculis 2023. 5. 27.

내 옆의 개발자, LINT 를 오픈하였습니다.

웹사이트가 필요하면 언제든 연락주세요.

주식 가격을 예측하고 랭크를 올리는 커뮤니티, 오떨 을 오픈하였습니다.

지금 접속하고 예측을 시작해보세요.

728x90

Next api?

웹 개발을 할 때는 Express & EJS를 이용해 프레임워크 없이 사이트를 만들곤 한다. 그런데 최근 SPA (single page application)의 장점을 깨닫고 한 달쯤 전부터 Next라는 프레임워크를 사용해보고 있는데, 풀리지 않는 궁금증 중 하나가 왜 api를 사용하냐? 하는 것이다.
 
예를 들면 json 파일을 읽거나 쓸 때, 그냥 fs 쓰면 안되나? 싶은데 그게 안된다는 걸 오늘 정확히 알았다.

Client vs Server

구글의 힘을 빌려 개발에 달려들다 보면 기초 지식이 많이 부족해지는데, 그 중 가장 중요한 개념이 client와 server를 구분하는 것이다. Client와 Server는 각각 프론트, 백으로 생각해도 되는데 이게 단순히 디자인이나 웹 구성의 문제가 아니라서 머리가 아파진다. 개발을 공부하면서 배운 대원칙이자 생각할 부분을 몇 가지 소개하자면
 

  1. Client에서 Server의 파일을 직접 읽거나 쓸 수 없다. 이걸 할 수 있다면 F12로 코드를 까서 로컬 파일을 다 지워버릴 수 있기 때문이다. 반드시 xhr이나 fetch를 이용한 POST나 GET 요청을 통해서만 가능하다.
  2. 그래서 로컬 파일에 접근하기 위해서는 요청을 받아줄 서버 장치가 필요하다. 컴퓨팅 기능을 할 줄 아는 장치라면 무엇이든 상관 없다. Firebase와 같은 DB에 내는 돈은 전부 서버 장치 값이다.
  3. Server에서 Client의 window나 document에 접근하는 것은 함수나 라이브러리를 통해 가능 하다. Express & EJS에서는 node-html-parser를 사용했고, Next나 React와 같은 프레임 워크에서는 useEffect를 사용했다.
     

마지막으로 Client와 Server의 중간자로 DB를 사용해야 하느냐? 하는게 문제인데, 보통 mongoDB같은 것을 많이 사용하는데 개인 프로젝트 규모의 작은 개발은 굳이 쓸 필요는 없는 것 같다. 비용도 비용인데 무엇보다 속도가 느리다. (Firebase같은 경우는 1초에 1번) 그냥 json파일을 이용하는 편이 더 나은데 이 부분은 계속 배우면서 생각을 바꿔나갈 예정이다.

Fetch

Express & EJS Next / React
백→프론트 node-html-parser useEffect
프론트→백 fetch fetch
미들웨어 router api
Auth Passport NextAuth

비교해보자면 이렇다. NextAuth랑 Passport 둘 다 맨땅에 헤딩하며 배우느라 참 어려웠는데, 이것도 기회되면 나중에 다루어보고, 오늘 얘기의 핵심은 프론트에서 서버의 데이터에 접근할 때 사용하는 fetch이다. 일단 코드를 보자. 구성은 이렇다.

순서는 Fetch (프) → API → Module (백) 순으로 생각하면 된다.

1. Fetch

// fetch.js or fetch.jsx
const Fetch = async (url, props) => {
    props = JSON.stringify(props || {});
    let res = await fetch(url, {
        body: props, method: 'post'
    });
    if (res.ok) {
        try {
            return await res.json();
        } catch {
            return res.status;
        }
    }
    return false;
}
await Fetch('/api/json', {url:'data.json'})

이런 코드를 하나 짜서 url에 props를 body로 하는 post request를 보낸다. Body에는 읽고자 하는 데이터의 url이 들어간다. 요청을 보낼 url과 다르다는 것이 핵심이다. 그럼 이 Fetch 함수를 어디서 이용하냐? 하면 바로 API에서 이용한다.

2. API

// Next
import json from '../module/json';

export default function handler(req, res) {
    let { url } = JSON.parse(req.body);
    res.status(200).send(json.read(url))
}
// Node
const app = require('express').Router();
const json = require('../module/json');

app.post('/read', (req, res) => {
    let { url } = JSON.parse(req.body);
    res.status(200).send(json.read(url))
})

API는 대략 이런 느낌이 된다. 우리가 Node에서 router와 app.use()를 이용해 각 url마다의 미들웨어를 정해줬는데, Next에서는 api 폴더를 설정해서 [...query]와 같은 방식으로 미들웨어의 기능을 파악하거나 그냥 모든 파일을 다 만들어서 요청을 백으로 보내준다. 쉽게 말해 api는 app.post와 같은 기능이다. 만약 api를 사용하지 않고 fs를 쓰면 이런 에러가 뜰 텐데,

TypeError:  fs__WEBPACK_IMPORTED_MODULE_6___default(...).readFileSync is not a function

우리가 자바스크립트 콘솔에서 fs.readFileSync를 쓰는 것과 마찬가지인 셈이다. 'fs/promise'를 쓰는 방법도 있다는데 써보니까 추천할만한 방법은 전혀 아니다. 다시 코드에서, json.read는 어디 있는 함수냐? 하면 마지막으로 백에서 만든 module로 가주자.

3. Module

// Next
import fs from 'fs';

export default json = {
    read: url => {
        return JSON.parse(fs.readFileSync(url));
    }
}
// Node
const fs = require('fs');

module.exports = {
    read: url => {
        return JSON.parse(fs.readFileSync(url));
    }
}

모듈은 차이가 전혀 없다. 그냥 commonJS방식이냐 아니면 es6방식이냐 차이일 뿐이다. 요청이 프론트→미들→백으로 들어와서 다시 백→미들→프론트로 나간다. 아마 나와 같이 fs왜 안됨? 과 같은 생각을 했다면 이런 통신 구조에는 익숙한데, 프레임워크를 쓰다 보면 전부 jsx를 사용하고 구분이 잘 안돼서 놓쳤을 가능성이 높다.
 
오늘은 Next를 배우면서 거의 가장 먼저 마주칠 장애물인 api에 대해 알아보았다. 다음에는 NextAuth에서 로컬데이터를 읽어오는 방법에 대해 passport와 비교하는 글을 써볼까 한다.

728x90

'웹개발 > Next' 카테고리의 다른 글

Next.js의 화나는 에러 : /_error: /404, /500  (0) 2023.07.01

댓글