API란?

Application Programming Interface의 약자로 응용 프로그래밍 인터페이스라는 뜻이다.
컴퓨터나 컴퓨터 프로그램을 연결하는 역할을 한다.
예를 들어, 고객이 어떠한 데이터를 요청했을때 DB에 접근하기 위해서는 프론트엔드가 백엔드와 연결되어야 하고, 백엔드에서 제공해주는 API를 통해 DB에 접근할 수 있어야 한다.

API Routes

Next.js는 서버와 독립적으로 실행할 수 있는(Serverless, 서버리스) API Routes를 제공한다.
즉, 추가적으로 백엔드 서버를 구축하지 않더라도 독립적으로 사용할 수 있는 나만의 API를 만들 수 있다 😲

pages/api 폴더 내의 모든 파일은 /api/*에 매핑되어 페이지 대신 API 엔드포인트로 처리된다.
이는 서버사이드 번들이므로 클라이언트측 번들 사이즈를 늘리지 않는다고 한다.

아래는 200 코드와 { name: 'John Doe' } 라는 JSON을 리턴하는 API다.

// pages/api/user.js

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

위 예제 코드처럼 API Route 기능을 사용하기 위해서는 일명 request handler 라고 하는 default function을 export해야 한다.
request handler는 req, res 라는 파라미터를 받는다.

실습

동물에 대한 정보를 조회하는 나만의 API를 만들어 보았다!

목 데이터 생성하기

DB를 사용하지 않기 때문에 조회할 수 있는 데이터를 아래와 같이 js 파일로 생성다.

 // src/data/index.js
 
 export const animals = [
    {
        id: '1',
        name: '댕댕이',
        mbti: 'ENFP',
        age: 4,
        imgSrc: 'https://images.unsplash.com/photo-1608831540955-35094d48694a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8ODN8fHB1cHB5fGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60'
    },
    {
        id: '2',
        name: '애옹이',
        mbti: 'INTJ',
        age: 1,
        imgSrc: 'https://images.unsplash.com/photo-1595433707802-6b2626ef1c91?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8a2l0dGVufGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60',
    },
    {
        id: '3',
        name: '다람이',
        mbti: 'ISFP',
        imgSrc: 'https://images.unsplash.com/photo-1507666405895-422eee7d517f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8JUVCJThCJUE0JUVCJTlFJThDJUVDJUE1JTkwfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60'
    },
    {
        id: '4',
        name: '곰곰이',
        mbti: 'ENTJ',
        imgSrc: 'https://images.unsplash.com/photo-1589656966895-2f33e7653819?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8cG9sYXIlMjBiZWFyfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=800&q=60'
    },
    {
        id: '5',
        name: '짹짹이',
        mbti: 'ESFP',
        imgSrc: 'https://images.unsplash.com/photo-1620694563886-c3a80ec55f41?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MzV8fGJpcmR8ZW58MHx8MHx8&auto=format&fit=crop&w=800&q=60'
    },
    {
        id: '6',
        name: '토심이',
        mbti: 'INFP',
        imgSrc: 'https://images.unsplash.com/photo-1596982061417-3a686a450552?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTJ8fHJhYmJpdHxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=800&q=60'
    },
    {
        id: '7',
        name: '다이노',
        mbti: 'ESTJ',
        imgSrc: 'https://images.unsplash.com/photo-1584844115436-473887b1e327?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTV8fCVFQSVCMyVCNSVFQiVBMyVBMXxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=800&q=60'
    }
]

pages/api 에 핸들러 생성하기

그리고 pages/api/animals 디렉토리에 아래와 같이 핸들러를 생성다.

import { animals } from "../../src/data";

export default function handler(req, res){
    return res.status(200).json(animals)
}


동물에 부여한 고유한 id로 해당 동물의 데이터를 조회할 수 있도록 pages/api/animals/[id].js 라는 파일을 생성해서 핸들러를 작성했다.

import { animals } from "../../src/data";

export default function animalsHandler(req, res){
    const {query} = req;
    const {id} = query;
    const animal = animals.find(({animal}) => animal.id === id);

    return animal? res.status(200).json(animal) : res.status(404).json({message: `${id} NOT FOUND`})  
}

참고로 req.query 는 기본값이 {}로 쿼리 스트링을 포함하는 객체이다.

클라이언트에서 호출하기

이제 데이터와 API는 준비되었으니 클라이언트에서 호출을 해보쟈!

// pages/animals/index.jsx

import Link from "next/link";
import { useEffect } from "react";
import useSWR from 'swr';
import AnimalPage from "./[id]";

const fetcher = (url) => fetch(url).then((res) => res.json());

const AnimalsPage = () => {
    const {data, error, isLoading} = useSWR('/api/animals', fetcher);

    if(error) return <p>일시적인 오류가 발생했습니다.</p>;
    if(isLoading) return <p>로딩중입니다 ...</p>;
    if(!data) return null;

    return (
        <ul>
            {
                data.map((animal) => <Link href={`/animals/${animal.id}`} key={animal.id} style=>{animal.name} 정보 더 보기</Link>)
            }
        </ul>
    )

}

export default AnimalsPage


개발자 도구의 네트워크 패널에서 확인해보면 데이터가 정상적으로 조회된 것을 확인할 수 있다!
image


각 동물의 상세 페이지 코드는 아래와 같다.

import { useRouter } from "next/router";
import useSWR from 'swr';

const fetcher = async (url) => {
    const res = await fetch(url);
    const data = await res.json();

    if(res.status !== 200) {
        throw new Error(data.message);
    }
    return data;
}

const AnimalPage = () => {
    const {query} = useRouter();
    const {data, error, isLoading, isValidating} = useSWR(() => (query.id ? `/api/animals/${query.id}` : null), fetcher);

    if(error) return <p>일시적인 오류가 발생했습니다.</p>;
    if(isLoading) return <p>로딩중입니다 ...</p>;
    if(!data) return null;

    return (
        <table>
            <thead>
                <tr>
                    <th>이름</th>
                     <th>MBTI</th>
                     <th>사진</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    {
                        isValidating ? 
                            <td>데이터를 가져오는 중입니다...</td> : 
                            <>
                            <td>{data.name}</td>
                            <td>{data.mbti}</td>
                            <td><img src={data.imgSrc} alt="animal_photo" width={200} height={200} style= /></td>
                            </>
                        
                    }
                </tr>
            </tbody>
        </table>
    )

}

export default AnimalPage;


각 상세 페이지도 정상적으로 조회된다.

image

이렇게 백엔드 서버와 독립적인 나만의 API를 만들어 보았다.
다음은 API Routes에 대해 이해한 내용을 기반으로 Next.js의 Preview Mode를 포스팅할 예정이다.

댓글남기기