<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>makee-ham.log</title>
        <link>https://velog.io/</link>
        <description>사랑! 용기! 희망!</description>
        <lastBuildDate>Sun, 27 Jul 2025 07:16:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>makee-ham.log</title>
            <url>https://velog.velcdn.com/images/makee-ham/profile/b591ef40-3e86-4bc4-9d3a-64ecc7ee08f9/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. makee-ham.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/makee-ham" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[프론트엔드 개발자를 위한 RESTful API 핵심 가이드: 원칙부터 라이브러리&도구까지]]></title>
            <link>https://velog.io/@makee-ham/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-RESTful-API-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%9B%90%EC%B9%99%EB%B6%80%ED%84%B0-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%8F%84%EA%B5%AC%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@makee-ham/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-RESTful-API-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%9B%90%EC%B9%99%EB%B6%80%ED%84%B0-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%8F%84%EA%B5%AC%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Sun, 27 Jul 2025 07:16:32 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<p>프론트엔드를 시작하면서 가장 처음 마주하는 벽 중 하나가 바로 <strong>API 통신</strong>이다. 화면에 데이터를 보여주려면 백엔드 서버에서 데이터를 가져와야 하는데, 이때 RESTful API를 사용하게 된다. 처음엔 GET, POST가 뭔지, 어떻게 데이터를 주고받아야 하는지 생소한 개념이 많아 막막할 수 있다. </p>
<p>이에 본 포스트에서는 <strong>RESTful API의 기본 개념</strong>부터 <strong>실무에서 사용하는 라이브러리와 도구들</strong>까지 차근차근 알아보고자 한다.</p>
<hr>
<h2 id="1-용어-정리-restful-api란">1. 용어 정리: RESTful API란?</h2>
<h3 id="rest의-정의">REST의 정의</h3>
<p><strong>REST</strong>는 <strong>Representational State Transfer</strong>의 줄임말로, 웹에서 자원을 효율적으로 주고받기 위한 아키텍처 스타일이다. 2000년 Roy Fielding이 제안한 개념으로, 현재 웹에서 가장 널리 사용되는 API 설계 방식이다.
<span style="color:silver;font-size:0.9rem;">참고: REST는 GraphQL, SOAP, gRPC 등 <a href="https://m.blog.naver.com/bluekms21/222543857436">다양한 API 아키텍처 스타일</a> 중에서도 가장 많이 사용된다.</span></p>
<h4 id="rest의-핵심-개념">REST의 핵심 개념</h4>
<ul>
<li><strong>자원(Resource)</strong>: 서버에 있는 데이터나 기능</li>
<li><strong>표현(Representation)</strong>: 자원의 현재 상태를 나타내는 형태 (주로 JSON)</li>
<li><strong>상태 전이(State Transfer)</strong>: 클라이언트가 서버의 자원 상태를 변경하는 것</li>
</ul>
<h3 id="restful-api의-정의">RESTful API의 정의</h3>
<p><strong>RESTful API</strong>는 이런 REST 원칙을 따라 만든 웹 API를 의미한다. 간단히 말해서 <strong>프론트엔드가 백엔드와 데이터를 주고받는 표준화된 방법</strong>이라고 생각하면 된다.</p>
<h3 id="restful-api의-특징">RESTful API의 특징</h3>
<p>RESTful API는 REST 원칙을 따르는 API로, 다음과 같은 특징을 가진다:</p>
<ol>
<li><strong>단순함</strong>: HTTP 메서드(POST, PUT, DELETE, GET, PATCH 등)만으로 모든 작업 표현</li>
<li><strong>무상태성</strong>: 각 요청이 독립적이며 서버가 클라이언트 상태를 저장하지 않음</li>
<li><strong>일관성</strong>: 동일한 패턴으로 API 설계</li>
<li><strong>확장성</strong>: 캐싱과 계층화가 용이함</li>
</ol>
<pre><code class="language-javascript">// RESTful API 예시
// 사용자 목록 조회
GET /api/users

// 특정 사용자 조회  
GET /api/users/123

// 새 사용자 생성
POST /api/users

// 사용자 수정
PUT /api/users/123

// 사용자 삭제
DELETE /api/users/123</code></pre>
<h3 id="rest-vs-restful의-차이">REST vs RESTful의 차이</h3>
<ul>
<li><strong>REST</strong>: 아키텍처 원칙 자체</li>
<li><strong>RESTful</strong>: REST 원칙을 잘 따르고 있는 시스템</li>
</ul>
<p>실제로는 완벽한 REST를 구현하기 어려워 대부분 &quot;REST-like&quot; 또는 &quot;RESTful&quot;이라고 표현한다.</p>
<h3 id="api의-역할">API의 역할</h3>
<p><strong>API</strong>(Application Programming Interface)는 두 애플리케이션이 서로 소통할 수 있게 해주는 인터페이스다. 웹 개발에서는 다음과 같이 동작한다:</p>
<ol>
<li><strong>클라이언트(프론트엔드)</strong>가 HTTP 요청을 보냄</li>
<li><strong>서버(백엔드)</strong>가 요청을 처리하고 HTTP 응답을 보냄</li>
<li>주고받는 데이터는 주로 <strong>JSON 형태</strong></li>
</ol>
<h3 id="핵심-특징">핵심 특징</h3>
<p>RESTful API의 핵심은 <strong>무상태성(Stateless)</strong>에 있다. 서버는 이전 요청을 기억하지 않으며, 모든 요청은 필요한 정보를 스스로 포함해야 한다. 예를 들어 인증이 필요한 요청이라면 매번 토큰을 함께 보내야 한다.
즉, 각 요청은 독립적이며 서버는 클라이언트의 상태를 저장하지 않는다.</p>
<p>이런 설계 덕분에 서버의 확장성이 높아지고, 클라이언트와 서버 간 의존성이 줄어든다.</p>
<hr>
<h2 id="2-rest-원칙과-http-메서드-활용">2. REST 원칙과 HTTP 메서드 활용</h2>
<h3 id="rest의-6가지-핵심-원칙">REST의 6가지 핵심 원칙</h3>
<h4 id="1-클라이언트-서버-구조">1. 클라이언트-서버 구조</h4>
<p>클라이언트와 서버가 독립적으로 진화할 수 있도록 분리된 구조다.</p>
<pre><code class="language-javascript">// 클라이언트 (ex. React 앱): 요청(request) 담당
const fetchUsers = async () =&gt; {
  const response = await fetch(&#39;/api/users&#39;);
  return response.json();
};

// 서버는 독립적으로 API만 제공: 응답(response) 담당</code></pre>
<h4 id="2-무상태성stateless">2. 무상태성(Stateless)</h4>
<p>서버는 클라이언트의 상태 정보를 저장하지 않는다. 모든 요청에 필요한 정보가 포함되어야 한다.</p>
<pre><code class="language-javascript">// 잘못된 예 - 서버가 상태를 기억해야 함
GET /api/users/next  // 이전 요청을 기억해야 함

// 올바른 예 - 모든 정보가 요청에 포함
GET /api/users?page=2&amp;limit=10</code></pre>
<h4 id="3-캐시-가능성cacheable">3. 캐시 가능성(Cacheable)</h4>
<p>요청을 통해 보내는 자료들은 캐싱이 가능해야 하며, 응답은 캐시 가능 여부를 명시해야 한다.</p>
<pre><code class="language-javascript">// HTTP 헤더로 캐싱 제어
fetch(&#39;/api/users&#39;, {
  headers: {
    &#39;Cache-Control&#39;: &#39;max-age=3600&#39;  // 1시간 캐싱
  }
});</code></pre>
<h4 id="4-계층화-시스템layered-system">4. 계층화 시스템(Layered System)</h4>
<p>클라이언트는 서버의 내부 구조를 알 필요가 없다.</p>
<pre><code>클라이언트 → 로드밸런서 → API 게이트웨이 → 서버</code></pre><p><span style="color:silver;font-size:0.9rem;">참고: <a href="https://twojun-space.tistory.com/158">로드밸런서</a></span></p>
<h4 id="5-일관된-인터페이스uniform-interface">5. 일관된 인터페이스(Uniform Interface)</h4>
<p>동일한 자원에 대해서는 하나의 URI만 사용한다.</p>
<pre><code class="language-javascript">// 일관된 인터페이스 예시
GET    /api/users      // 사용자 목록
POST   /api/users      // 사용자 생성
GET    /api/users/123  // 특정 사용자 조회
PUT    /api/users/123  // 특정 사용자 전체 수정
DELETE /api/users/123  // 특정 사용자 삭제</code></pre>
<ul>
<li><strong>자원(Resource)</strong>: URI로 식별함 + <u>명사</u> 형태 (예: <code>/users</code>)</li>
<li><strong>행위(Action)</strong>: HTTP 메서드로 표현함 + <u>동사</u> 형태 (예: GET, POST)</li>
</ul>
<p>URI는 명사를 사용하고, 동사는 HTTP 메서드가 담당한다. 예를 들어 <code>DELETE /deleteUser/1</code> 대신 <code>DELETE /users/1</code>처럼 설계한다.</p>
<h4 id="6-코드-온-디맨드-선택적">6. 코드 온 디맨드 (선택적)</h4>
<p>서버가 클라이언트에게 실행 가능한 코드를 전송할 수 있다. (JavaScript 등)</p>
<h3 id="http-메서드별-역할">HTTP 메서드별 역할</h3>
<h4 id="get---조회">GET - 조회</h4>
<pre><code>GET /users        → 전체 사용자 목록 조회
GET /users/1      → ID가 1인 사용자 정보 조회</code></pre><ul>
<li>데이터를 가져올 때(조회할 때) 사용</li>
<li>서버 상태를 변경하지 않음</li>
<li>브라우저에 캐시 가능</li>
</ul>
<h4 id="post---생성">POST - 생성</h4>
<pre><code>POST /users       → 새로운 사용자 생성</code></pre><ul>
<li>새로운 리소스를 만들 때 사용</li>
<li>요청 본문(body)에 생성할 데이터를 포함</li>
</ul>
<h4 id="put---전체-수정">PUT - 전체 수정</h4>
<pre><code>PUT /users/1      → ID가 1인 사용자 정보 전체 교체</code></pre><ul>
<li>기존 리소스를 완전히 교체</li>
<li>모든 필드를 새로운 값으로 덮어씀 (∴ 모든 필드를 포함해야 함)</li>
</ul>
<h4 id="patch---부분-수정">PATCH - 부분 수정</h4>
<pre><code>PATCH /users/1    → ID가 1인 사용자 정보 일부 수정</code></pre><ul>
<li>리소스의 일부만 변경</li>
<li>예: 이메일만 수정하고 싶을 때</li>
</ul>
<h4 id="delete---삭제">DELETE - 삭제</h4>
<pre><code>DELETE /users/1   → ID가 1인 사용자 삭제</code></pre><ul>
<li>리소스를 삭제할 때 사용</li>
<li>삭제 성공 후 일반적으로 response.status는 204 No Content 반환</li>
</ul>
<h3 id="http-상태-코드">HTTP 상태 코드</h3>
<p>API 응답에는 상태 코드가 포함되어 요청 결과를 알 수 있다. 아래는 자주 쓰이는 상태 코드들이다:</p>
<h4 id="2xx-성공">2xx 성공</h4>
<ul>
<li><strong>200 OK</strong>: 요청 성공</li>
<li><strong>201 Created</strong>: 자원 생성 성공</li>
<li><strong>204 No Content</strong>: 성공했지만 반환할 내용 없음</li>
</ul>
<h4 id="4xx-클라이언트-오류">4xx 클라이언트 오류</h4>
<ul>
<li><strong>400 Bad Request</strong>: 잘못된 요청</li>
<li><strong>401 Unauthorized</strong>: 인증 필요</li>
<li><strong>403 Forbidden</strong>: 권한 없음</li>
<li><strong>404 Not Found</strong>: 자원을 찾을 수 없음</li>
</ul>
<h4 id="5xx-서버-오류">5xx 서버 오류</h4>
<ul>
<li><strong>500 Internal Server Error</strong>: 서버 내부 오류</li>
<li><strong>502 Bad Gateway</strong>: 게이트웨이 오류</li>
<li><strong>503 Service Unavailable</strong>: 서비스 이용 불가</li>
</ul>
<hr>
<h2 id="3-데이터-페칭-라이브러리-활용법">3. 데이터 페칭 라이브러리 활용법</h2>
<h3 id="서버-상태-관리의-필요성">서버 상태 관리의 필요성</h3>
<p>프론트엔드에서 다루는 상태는 크게 두 가지로 나뉜다:</p>
<ul>
<li><strong>클라이언트 상태</strong>: 프론트엔드에서 직접 제어하는 상태 (UI 상태, 폼 입력값 등)</li>
<li><strong>서버 상태</strong>: 백엔드에서 가져오는 데이터 (사용자 정보, 게시글 목록 등)</li>
</ul>
<p>서버 상태는 클라이언트에서 직접 제어할 수 없고, 언제든 변할 수 있다. 이를 효율적으로 관리하기 위해 전용 라이브러리를 사용한다.</p>
<h4 id="기존-방식의-문제점">기존 방식의 문제점</h4>
<p>기본적으로는 <code>fetch</code>나 <code>axios</code>를 사용해 API를 호출할 수 있다:</p>
<pre><code class="language-javascript">// 기본 fetch 사용 예시
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() =&gt; {
  fetch(&#39;/api/users&#39;)
    .then(res =&gt; res.json())
    .then(data =&gt; {
      setUsers(data);
      setLoading(false);
    })
    .catch(err =&gt; {
      setError(err);
      setLoading(false);
    });
}, []);</code></pre>
<p>하지만 이런 방식은 다음과 같은 문제가 있다:</p>
<ul>
<li>매번 로딩/에러 상태를 관리해야 함</li>
<li>캐싱 기능이 없어 같은 데이터를 중복 요청함</li>
<li>데이터 동기화(백그라운드 상의 데이터 업데이트)가 어려움</li>
<li>에러 재시도 로직(에러 핸들링) 직접 구현해야 함</li>
</ul>
<h4 id="데이터-페칭-라이브러리가-해결하는-문제들">데이터 페칭 라이브러리가 해결하는 문제들</h4>
<ol>
<li><strong>캐싱</strong>: 같은 데이터를 여러 컴포넌트에서 사용해도 한 번만 요청</li>
<li><strong>백그라운드 업데이트</strong>: 사용자의 별도 조작 없이도 데이터를 최신으로 유지</li>
<li><strong>중복 요청 제거</strong>: 동일한 요청이 동시에 여러 번 발생하지 않도록 방지</li>
<li><strong>에러 핸들링</strong>: 자동 재시도, 에러 상태 관리</li>
<li><strong>로딩 상태</strong>: 복잡한 로딩 상태를 간단하게 관리</li>
<li><strong>메모리 관리</strong>: 사용하지 않는 데이터는 자동으로 정리</li>
<li><strong>Optimistic Updates</strong>: 서버 응답을 기다리지 않고 UI를 먼저 업데이트</li>
</ol>
<h3 id="tanstack-query-구-react-query">TanStack Query (구 React Query)</h3>
<p><strong>TanStack Query</strong>는 서버 상태 관리를 위한 가장 인기 있는 라이브러리다. 기존의 Redux나 Context API가 클라이언트 상태를 관리한다면, React Query는 서버에서 가져온 데이터의 상태를 관리한다.
TanStack Query를 통해 데이터 fetching, 캐싱, 동기화, 업데이트를 간편하게 처리할 수 있다.</p>
<h4 id="기본-설정">기본 설정</h4>
<pre><code class="language-bash">npm install @tanstack/react-query</code></pre>
<pre><code class="language-javascript">// App.js - React Query 설정 상세 설명
import { QueryClient, QueryClientProvider } from &#39;@tanstack/react-query&#39;;
import { ReactQueryDevtools } from &#39;@tanstack/react-query-devtools&#39;;

// QueryClient 생성 - 모든 쿼리의 설정과 캐시를 관리
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // staleTime: 데이터가 &quot;신선한&quot; 상태로 유지되는 시간
      // 이 시간 내에는 다시 요청하지 않음 (기본값: 0)
      staleTime: 1000 * 60 * 5, // 5분

      // cacheTime: 컴포넌트가 언마운트된 후 캐시를 유지하는 시간
      // 이 시간이 지나면 가비지 컬렉션됨 (기본값: 5분)
      cacheTime: 1000 * 60 * 10, // 10분

      // retry: 요청 실패 시 재시도 횟수 (기본값: 3)
      retry: 1,

      // refetchOnWindowFocus: 윈도우가 포커스될 때 자동 새로고침 여부
      refetchOnWindowFocus: false,

      // refetchOnReconnect: 네트워크 재연결 시 자동 새로고침 여부
      refetchOnReconnect: true,

      // refetchInterval: 주기적 새로고침 간격 (밀리초, false면 비활성화)
      refetchInterval: false,
    },
    mutations: {
      // 뮤테이션 실패 시 재시도 횟수
      retry: 1,
    },
  },
});

function App() {
  return (
    &lt;QueryClientProvider client={queryClient}&gt;
      &lt;YourApp /&gt;
      {/* 개발 도구 - 쿼리 상태를 시각적으로 확인 가능 */}
      &lt;ReactQueryDevtools initialIsOpen={false} /&gt;
    &lt;/QueryClientProvider&gt;
  );
}</code></pre>
<h4 id="사용-예시-usequery">사용 예시: useQuery</h4>
<p><strong>useQuery가 하는 일:</strong></p>
<ol>
<li>컴포넌트가 마운트되면 자동으로 데이터 요청</li>
<li>같은 쿼리 키를 가진 다른 컴포넌트들과 데이터 공유</li>
<li>백그라운드에서 데이터 업데이트 확인</li>
<li>에러 발생 시 자동 재시도</li>
<li>로딩, 에러, 성공 상태 자동 관리</li>
</ol>
<pre><code class="language-javascript">import { useQuery } from &#39;@tanstack/react-query&#39;;

// API 함수 - 실제 서버 요청을 담당
const fetchUsers = async ({ queryKey }) =&gt; {
  // queryKey는 useQuery의 첫 번째 인자로 전달된 배열
  const [_key, params] = queryKey;

  const url = new URL(&#39;/api/users&#39;, window.location.origin);
  if (params) {
    Object.entries(params).forEach(([key, value]) =&gt; {
      url.searchParams.append(key, value); // value는 string이어야
    });
  }

  const response = await fetch(url);

  // 응답이 실패했을 때 에러를 던져야 React Query가 인식함
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: 사용자 목록을 불러올 수 없습니다`);
  }

  return response.json();
};

// 컴포넌트에서 사용
function UserList() {
  const {
    // 서버에서 받은 실제 데이터
    data: users,

    // 현재 로딩 중인지 여부 (최초 로딩)
    isLoading,

    // 백그라운드에서 새로고침 중인지 여부
    isFetching,

    // 에러 객체 (에러가 없으면 null)
    error,

    // 에러가 발생했는지 여부
    isError,

    // 데이터가 성공적으로 로드되었는지 여부
    isSuccess,

    // 수동으로 다시 요청하는 함수
    refetch,

    // 쿼리가 비활성화되었는지 여부
    isEnabled,

    // 데이터가 &quot;stale&quot;(오래된) 상태인지 여부
    isStale,
  } = useQuery({
    // 쿼리 키 - 캐싱과 식별을 위한 고유한 키
    // 배열 형태로, 종속성이 있으면 배열에 포함
    queryKey: [&#39;users&#39;, { page: 1, limit: 10 }],

    // 실제 데이터를 가져오는 함수
    queryFn: fetchUsers,

    // 이 쿼리만의 설정 (전역 설정을 덮어씀)
    staleTime: 1000 * 60 * 5, // 5분간 신선함 유지
    cacheTime: 1000 * 60 * 10, // 10분간 캐시 유지

    // 쿼리 실행 조건 (false면 실행하지 않음)
    enabled: true,

    // 에러 발생 시 재시도 조건
    retry: (failureCount, error) =&gt; {
      // 404 에러는 재시도하지 않음
      if (error.message.includes(&#39;404&#39;)) return false;
      // 3번까지만 재시도
      return failureCount &lt; 3;
    },

    // 재시도 간격 (기본값: 1초, 2초, 4초...)
    retryDelay: attemptIndex =&gt; Math.min(1000 * 2 ** attemptIndex, 30000),
  });

  // 로딩 상태 처리
  if (isLoading) {
    return (
      &lt;div className=&quot;loading&quot;&gt;
        &lt;div&gt;사용자 목록을 불러오는 중...&lt;/div&gt;
        &lt;div&gt;잠시만 기다려주세요&lt;/div&gt;
      &lt;/div&gt;
    );
  }

  // 에러 상태 처리
  if (isError) {
    return (
      &lt;div className=&quot;error&quot;&gt;
        &lt;h3&gt;오류가 발생했습니다&lt;/h3&gt;
        &lt;p&gt;{error.message}&lt;/p&gt;
        &lt;button onClick={() =&gt; refetch()}&gt;다시 시도&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  // 성공 상태 - 데이터 렌더링
  return (
    &lt;div&gt;
      &lt;div className=&quot;header&quot;&gt;
        &lt;h2&gt;사용자 목록 ({users?.length || 0}명)&lt;/h2&gt;
        &lt;button 
          onClick={() =&gt; refetch()} 
          disabled={isFetching}
        &gt;
          {isFetching ? &#39;새로고침 중...&#39; : &#39;새로고침&#39;}
        &lt;/button&gt;
        {isStale &amp;&amp; &lt;span&gt;⚠️ 오래된 데이터를 조회하고 있습니다&lt;/span&gt;}
      &lt;/div&gt;

      &lt;div className=&quot;user-list&quot;&gt;
        {users?.map(user =&gt; (
          &lt;div key={user.id} className=&quot;user-item&quot;&gt;
            &lt;h4&gt;{user.name}&lt;/h4&gt;
            &lt;p&gt;{user.email}&lt;/p&gt;
            &lt;span className=&quot;role&quot;&gt;{user.role}&lt;/span&gt;
          &lt;/div&gt;
        ))}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h4 id="주요-기능">주요 기능</h4>
<ul>
<li><strong>자동 캐싱</strong>: 같은 queryKey로 여러 번 호출해도 한 번만 요청이 들어감</li>
<li><strong>백그라운드 업데이트</strong>: 화면에 데이터를 보여주면서 뒤에서 최신 데이터로 갱신</li>
<li><strong>Mutation 지원</strong>: POST, PUT, DELETE 같은 서버 리소스 변경 작업 처리</li>
<li><strong>개발자 도구</strong> (<code>&lt;ReactQueryDevtools/&gt;</code>): 쿼리 상태를 시각적으로 확인 가능</li>
</ul>
<h3 id="swr">SWR</h3>
<p><strong>SWR</strong>(Stale-While-Revalidate)은 Vercel에서 만든 가벼운 데이터 페칭 라이브러리다.
이름에서 알 수 있듯, 캐시된 데이터를 먼저 보여주고(showing stale data―), 백그라운드에서 최신 데이터를 가져와 갱신(―while revalidating)하는 전략을 사용한다.</p>
<p><strong>SWR의 핵심 철학:</strong></p>
<ol>
<li><strong>빠른 응답</strong>: 캐시된 데이터를 즉시 보여줌</li>
<li><strong>최신성 보장</strong>: 백그라운드에서 서버와 동기화</li>
<li><strong>단순함</strong>: 최소한의 설정으로 강력한 기능 제공</li>
<li><strong>자동화</strong>: 포커스, 네트워크 재연결 시 자동 업데이트</li>
</ol>
<h4 id="사용-예시">사용 예시</h4>
<pre><code class="language-bash">npm install swr</code></pre>
<pre><code class="language-javascript">import useSWR from &#39;swr&#39;;

// fetcher 함수 - SWR에게 &quot;어떻게 데이터를 가져올지&quot; 알려주는 함수
const fetcher = (url) =&gt; fetch(url).then(res =&gt; {
  if (!res.ok) {
    throw new Error(&#39;데이터를 불러오는데 실패했습니다&#39;);
  }
  return res.json();
});

function UserList() {
  // SWR의 기본 사용법
  const { 
    data,           // 서버에서 받은 데이터
    error,          // 에러 객체
    isLoading,      // 최초 로딩 중인지 (data와 error가 모두 undefined)
    isValidating,   // 백그라운드에서 재검증 중인지
    mutate          // 수동으로 데이터 갱신하는 함수
  } = useSWR(&#39;/api/users&#39;, fetcher);

  // 로딩 상태
  if (isLoading) return &lt;div&gt;사용자 목록을 불러오는 중...&lt;/div&gt;;

  // 에러 상태
  if (error) return (
    &lt;div&gt;
      &lt;p&gt;에러가 발생했습니다: {error.message}&lt;/p&gt;
      &lt;button onClick={() =&gt; mutate()}&gt;다시 시도&lt;/button&gt;
    &lt;/div&gt;
  );

  return (
    &lt;div&gt;
      &lt;div className=&quot;header&quot;&gt;
        &lt;h2&gt;사용자 목록&lt;/h2&gt;
        {/* 백그라운드 업데이트 상태 표시 */}
        {isValidating &amp;&amp; &lt;span&gt;🔄 업데이트 중...&lt;/span&gt;}
        &lt;button onClick={() =&gt; mutate()}&gt;새로고침&lt;/button&gt;
      &lt;/div&gt;

      &lt;div className=&quot;user-list&quot;&gt;
        {data?.map(user =&gt; (
          &lt;div key={user.id} className=&quot;user-item&quot;&gt;
            &lt;h4&gt;{user.name}&lt;/h4&gt;
            &lt;p&gt;{user.email}&lt;/p&gt;
            &lt;span className=&quot;role&quot;&gt;{user.role}&lt;/span&gt;
          &lt;/div&gt;
        ))}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h3 id="tanstack-query-vs-swr">TanStack Query vs SWR</h3>
<table>
<thead>
<tr>
<th>특징</th>
<th>TanStack Query</th>
<th>SWR</th>
</tr>
</thead>
<tbody><tr>
<td>초기 설정</td>
<td>Provider 필요</td>
<td>바로 사용 가능</td>
</tr>
<tr>
<td>기능</td>
<td>풍부함 (Mutation, Pagination 등)</td>
<td>단순함</td>
</tr>
<tr>
<td>번들 크기</td>
<td>상대적으로 큼</td>
<td>가벼움</td>
</tr>
<tr>
<td>학습 곡선</td>
<td>조금 더 복잡</td>
<td>쉬움</td>
</tr>
</tbody></table>
<p>간단한 데이터 조회 위주라면 SWR, 복잡한 상태 관리가 필요하다면 TanStack Query를 선택하는 것이 좋다.</p>
<hr>
<h2 id="4-도구-활용-방법">4. 도구 활용 방법</h2>
<h3 id="swagger-ui-openapi">Swagger UI (OpenAPI)</h3>
<p><strong>Swagger UI</strong>는 RESTful API를 문서화하고 테스트할 수 있는 도구다. 백엔드 개발자가 Swagger를 적용하면, API 명세서가 자동으로 생성되고 웹 UI에서 인터랙티브한 문서를 확인할 수 있다.</p>
<h4 id="주요-기능-1">주요 기능</h4>
<ul>
<li><strong>API 문서 자동 생성</strong>: 엔드포인트, 파라미터, 응답 스키마 등을 한눈에 확인</li>
<li><strong>Try it out</strong>: 브라우저에서 직접 API 호출 테스트 가능</li>
<li><strong>스키마 확인</strong>: 요청/응답 데이터 구조를 명확히 파악</li>
</ul>
<h4 id="활용-방법">활용 방법</h4>
<ol>
<li>백엔드에서 제공하는 Swagger UI URL 접속 (보통 <code>/swagger-ui.html</code>)</li>
<li>필요한 API 엔드포인트 찾기</li>
<li>파라미터와 예시 확인</li>
<li>&quot;Try it out&quot; 버튼으로 직접 테스트</li>
</ol>
<p>예를 들어 <code>POST /users</code> API를 테스트하고 싶다면:</p>
<ol>
<li>해당 섹션 클릭</li>
<li>&quot;Try it out&quot; 버튼 클릭</li>
<li>요청 본문에 JSON 데이터 입력</li>
<li>&quot;Execute&quot; 버튼으로 실행</li>
<li>응답 결과 확인</li>
</ol>
<p>이를 통해 프론트엔드 코드 작성 전에 API 동작을 미리 확인할 수 있다.</p>
<h3 id="postman">Postman</h3>
<p><strong>Postman</strong>은 API 개발을 위한 협업 플랫폼이다. API 테스트, 문서화, 모니터링, 모킹 등 API 개발 생명주기 전반을 지원한다. HTTP 요청을 쉽게 만들어 보내고 응답을 확인할 수 있어 테스팅에 상당히 유용하다.</p>
<h4 id="기본-사용법">기본 사용법</h4>
<ol>
<li><strong>메서드와 URL 설정</strong>: GET, POST 등 선택하고 API URL 입력</li>
<li><strong>헤더 설정</strong>: Authorization, Content-Type 등 필요한 헤더 추가</li>
<li><strong>본문 설정</strong>: POST나 PUT 요청시 JSON 데이터 입력</li>
<li><strong>Send 클릭</strong>: 요청 보내고 응답 확인</li>
</ol>
<h4 id="실제-사용-예시">실제 사용 예시</h4>
<p><strong>GET 요청 - 사용자 목록 조회</strong></p>
<pre><code>Method: GET
URL: https://api.example.com/users
Headers: 
  Authorization: Bearer your_token_here</code></pre><p><strong>POST 요청 - 새 사용자 생성</strong></p>
<pre><code>Method: POST
URL: https://api.example.com/users
Headers:
  Content-Type: application/json
  Authorization: Bearer your_token_here
Body (raw JSON):
{
  &quot;name&quot;: &quot;홍길동&quot;,
  &quot;email&quot;: &quot;hong@example.com&quot;
}</code></pre><h4 id="유용한-기능">유용한 기능</h4>
<ul>
<li><strong>API 테스트</strong>: 다양한 HTTP 요청 테스트</li>
<li><strong>컬렉션</strong>: 관련된 API들을 폴더별로 묶어서 관리(연관 API 요청들을 그룹화)</li>
<li><strong>환경 변수</strong>: 개발/스테이징/프로덕션 환경별로 다른 URL 설정 가능</li>
<li><strong>코드 생성</strong>: 테스트한 요청을 JavaScript, Python 등 코드로 변환</li>
<li><strong>자동화</strong>: 테스트 스크립트와 워크플로우 자동화</li>
<li><strong>팀 공유</strong>: 컬렉션을 팀원들과 공유, 협업 용이</li>
<li><strong>문서화</strong>: 자동 API 문서 생성</li>
</ul>
<h4 id="프론트엔드-개발에서의-활용">프론트엔드 개발에서의 활용</h4>
<ol>
<li><strong>API 동작 확인</strong>: 백엔드 API가 제대로 작동하는지 먼저 테스트</li>
<li><strong>에러 디버깅</strong>: 프론트엔드에서 문제가 생겼을 때 API 자체의 문제인지 확인</li>
<li><strong>코드 생성</strong>: Postman에서 테스트한 요청을 fetch나 axios 코드로 변환</li>
</ol>
<hr>
<h2 id="나가며">나가며</h2>
<p>RESTful API는 현대 웹 개발에서 핵심적인 역할을 한다. 기본 원칙을 이해하고, 적절한 도구와 라이브러리를 활용하면 효율적인 개발이 가능하다.</p>
<p><strong>학습 및 실습 포인트 정리 for FE devs:</strong></p>
<ol>
<li>REST 기본 개념과 HTTP 메서드 이해</li>
<li>TanStack Query나 SWR로 데이터 페칭 경험 (프로젝트에 적합한 도구로 선택해야 함)</li>
<li>Swagger 문서 읽고 다루는 법 익히기</li>
<li>Postman으로 API 테스트 습관화</li>
</ol>
<p>실제 프로젝트에서는 이 모든 개념들이 유기적으로 연결된다. Swagger 문서를 보고 API를 이해한 후, 적절한 데이터 페칭 라이브러리를 선택하여 구현하고, Postman으로 테스트하는 것이 일반적인 워크플로우다.
특히 팀 협업에서는 API 명세서 공유, 테스트 케이스 문서화, 에러 상황 대응 등이 매우 중요하므로, 도구들을 단순히 &#39;사용&#39;하는 것을 넘어서 팀 전체의 개발 효율성을 높이는 방향으로 &#39;활용&#39;해야 한다.</p>
<p>처음엔 당연히 복잡해 보이지만, <strong>직접 API를 호출해보고, 에러를 경험하고, 해결하는 과정</strong>을 거쳐 하나씩 실습하다보면 자연스럽게 손에 익으리라 생각한다.</p>
<p>REST API를 제대로 이해하고 활용할 수 있다면, 어떤 백엔드와도 효과적으로 소통할 수 있는 프론트엔드 개발자가 될 수 있을 것이다.😎</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[안녕하세요 velog로 오늘 이사 온 새댁이에요 제 남편은 JavaScript고요 요즘엔 집에 React.js라는 서재를 마련했어요]]></title>
            <link>https://velog.io/@makee-ham/%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94-velog%EB%A1%9C-%EC%98%A4%EB%8A%98-%EC%9D%B4%EC%82%AC-%EC%98%A8-%EC%83%88%EB%8C%81%EC%9D%B4%EC%97%90%EC%9A%94-%EC%A0%9C-%EB%82%A8%ED%8E%B8%EC%9D%80-JavaScript%EA%B3%A0%EC%9A%94-%EC%9A%94%EC%A6%98%EC%97%94-%EC%A7%91%EC%97%90-React.js%EB%9D%BC%EB%8A%94-%EC%84%9C%EC%9E%AC%EB%A5%BC-%EB%A7%88%EB%A0%A8%ED%96%88%EC%96%B4%EC%9A%94</link>
            <guid>https://velog.io/@makee-ham/%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94-velog%EB%A1%9C-%EC%98%A4%EB%8A%98-%EC%9D%B4%EC%82%AC-%EC%98%A8-%EC%83%88%EB%8C%81%EC%9D%B4%EC%97%90%EC%9A%94-%EC%A0%9C-%EB%82%A8%ED%8E%B8%EC%9D%80-JavaScript%EA%B3%A0%EC%9A%94-%EC%9A%94%EC%A6%98%EC%97%94-%EC%A7%91%EC%97%90-React.js%EB%9D%BC%EB%8A%94-%EC%84%9C%EC%9E%AC%EB%A5%BC-%EB%A7%88%EB%A0%A8%ED%96%88%EC%96%B4%EC%9A%94</guid>
            <pubDate>Thu, 05 Jun 2025 07:11:32 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요 막희입니다</p>
<p>사랑 용기 희망 행복을 위해 미래를 준비하고 있는 평범한 사람이에요</p>
<p>성은 함씨여서 풀네임은 함막희예요
본명 아닙니다 근데 실제로 함씨긴 해요</p>
<p>아이고 제가 명함이 아직 없네요
대신 <a href="https://github.com/makee-ham">깃허브 주소</a>를 드리겠습니다</p>
<p>velog가 마크다운 지원도 잘해주고 쓰기 편해 보여서 여기로 왔습니다
또 부트캠프 하고 개인 프로젝트 하면서 기록 남기기도 좋아 보여서요</p>
<p>사실 그냥 처음에 아무 데서나 블로그 써봐야지 하고 Medium 썼다가
거긴 좀 고인물용 article 쓰는 데 같아서 도망친 건 안 비밀이에요</p>
<p>전 수상한 사람 아니고요
그냥 타닥타닥 타자 치는 거 넘 재밌어서 프론트엔드 개발 공부 시작한 사람입니다
피아니스트 같지 않나요
가끔 음악 들으면서 코딩할 때 리듬 따라 흐느적거리기도 해요</p>
<p>학부 전공은 국어국문학과였고요
대충 초록색을 테마로 한 여대 나왔고요
스타트업에서 한 번 PR 에이전시에서 한 번 인턴으로 일한 문과 중의 문과입니다</p>
<p>스타트업 때 잠시 UXUI 디자이너와 개발자들과 협업할 기회를 쟁취했는데
그때 참 재밌었던 기억이 있어서
퍼블리셔 과정인지 뭔지도 모르고 냅다 국비지원 학원 다녔다가
오 세상에 이렇게 재미있는 걸 너네만 하고 있었어? 같은 느낌으로
온종일 Figma나 시커먼 vs code 화면 쳐다보고 있던 추억</p>
<p>그 추억에 힘입어
지금은 OZ코딩스쿨이라는 데에서 6개월 과정 프론트엔드 부트캠프 들어가서
죽어라 열심히 쉬엄쉬엄 재밌고 즐겁게 공부하고 있습니다</p>
<p>진짜 재밌어요 장난 아니에요
맥북도 마련해서 저 이제 스타벅스도 막 들어간다고요</p>
<p>그리고 정말 재밌는 포인트는
이전에 이해가 하나도 안 됐던 게 이해가 되는 순간이 꽤 많다는 거예요
제가 새싹이어서 그렇겠지만
일단 이론 읽고 이해 안 돼도 실제로 써보고 다시 이론 보면 이해가 되는 매직
이것이 바로 이공계의 즐거움인가 하나하나 새로이 깨달아가고 있어요</p>
<p>Radiohead랑 프로그레시브한 음악, 그리고 음성합성엔진으로부터 발전한 JPop 일부 좋아하고요
아메리칸 뷰티, 파이트 클럽, 서스페리아2018, 시민 케인, 살인마 잭의 집(라스 폰 트리에 좋아해요 끝났죠) 등 영화도 좋아하고요
에반게리온, 진격의 거인, 돌아가는 펭귄드럼 등과 같이 얘기할 거리 많은 애니도 좋아하고요
최근엔 제가 태어난 연도에 나온 애니메이션 Serial experiments lain을 보고 있어요</p>
<p>이런
오랜만에 글을 쓰니 신이 나서 아무 말을 해버렸네요
아무튼 이런 사람입니다</p>
<p><a href="https://medium.com/@hamseoyeon18">이전 블로그 링크</a>
혹시 이전 블로그 궁금하시면 위 링크를 클릭해 주시고요</p>
<p><a href="https://www.postype.com/@makee-ham">포스타입 링크</a>
혹시 이 인간이 어떤 글을 쓰나 궁금하시면 위 링크를 클릭해 주시고요</p>
<p><a href="https://tumblbug.com/ddbs">대담백서 텀블벅 링크</a>
혹시 얘가 TRPG에 빠졌을 때 친구들이랑 출판사 만들어서 룰북 만든 게 뭔지 궁금하시면 위 링크를 클릭해 주시고요</p>
<p><a href="https://youtu.be/nYwKLBYxPRY?si=ChptGrtYj7PdIZeW">노래 부른 거 유튜브 링크</a>
혹시 이 사람이 노래 부른 거 궁금하시면 위 링크를 클릭해 주시고요</p>
<p>마침표 없는 글 읽어주셔서 감사합니다
곧 마지막 인사드릴 때 마침표를 타이핑할 줄 앎을 보여드리겠습니다</p>
<p>잘 부탁드립니다.</p>
]]></description>
        </item>
    </channel>
</rss>