✏️ 흐름
[Client] ----> [/api/test] ----> [Backend API]
(page.jsx) (route.js) (실제 데이터 처리)
- 클라이언트가 백엔드 API와 직접 통신하지 않도록 중간 서버(Next.js의 API Routes)를 두어 인증 및 데이터 요청을 처리하는 Next.js 애플리케이션 설계
📒 핵심 개념 요약
Next.js API Routes: 클라이언트와 백엔드 간의 중계 역할 수행
route.js: 클라이언트가 직접 백엔드와 통신하지 않고, Next.js 서버를 통해 데이터를 요청하도록 만듦
→ 이 방식을 통해 보안(인증 토큰 관리), API 통합 관리를 간소화할 수 있음
page.jsx: Next.js의 클라이언트 컴포넌트, UI 렌더링과 API 호출 로직을 포함
✏️ 전체 통신 구조
✅ 클라이언트에서 /api/test 로 요청
- 브라우저(클라이언트)가 /api/test로 요청을 보냅니다.
- 이 요청은 Next.js의 route.js로 전달됩니다.
- 주요 흐름
- useEffect로 데이터 요청
- 페이지가 처음 렌더링될 때 실행됩니다.
- 브라우저에서 /api/test로 fetch 요청을 보냅니다.
- 이 요청은 Next.js의 API 라우트(route.js)로 전달됩니다.
- fetch의 응답 처리
- 서버에서 응답받은 데이터를 JSON으로 변환합니다.
- 응답의 상태 코드에 따라 다음과 같이 처리합니다.
- 400 이상: 서버에서 보낸 리다이렉트 URL을 통해 다른 페이지로 이동합니다.
- 200: 데이터를 setRes를 통해 상태로 저장합니다.
- 상태 관리와 렌더링
- res 상태에 저장된 데이터가 변경될 때마다 로그를 출력합니다.
- UI에서 두 버튼을 클릭하면 각각 AlertModal과 BottomDrawer 컴포넌트를 제어합니다.
- useEffect로 데이터 요청
✅ Next.js 서버에서 백엔드로 요청
- route.js: 클라이언트 요청을 처리하며, 필요 시 백엔드 서버(process.env.SERVER_URL)로 데이터를 요청합니다.
- 백엔드에서 인증된 데이터를 받아옵니다.
- 주요 흐름
- 사용자 인증 (auth 호출)
- auth() 함수로 현재 세션 정보를 가져옵니다.
- 인증 토큰 (accessToken)을 포함한 세션 정보를 획득합니다.
- 백엔드 서버로 데이터 요청
- 환경 변수 SERVER_URL을 기반으로 백엔드의 API 엔드포인트 (/v1/api/member/info)로 요청을 보냅니다.
- 요청의 헤더에 인증 토큰을 추가하여 인증된 요청을 보냅니다.
- 응답 처리 및 전달
- 백엔드로부터 받은 응답 데이터를 JSON으로 변환합니다.
- 응답 상태 코드에 따라 클라이언트로 전달할 내용을 결정합니다.
- 400 이상: 클라이언트가 리다이렉트할 URL을 JSON 형태로 반환합니다.
- 200: 백엔드에서 받은 데이터를 클라이언트로 그대로 전달합니다.
- 사용자 인증 (auth 호출)
✅ 클라이언트로 응답 반환
- 백엔드 응답에 따라 클라이언트가 필요한 데이터를 반환하거나, 리다이렉트 URL을 제공합니다.
✏️ 비동기 처리와 HTTP 요청
📒 Promise
미래에 완료될 작업을 나타냅니다.
비동기 함수는 Promise를 반환하고, 이 Promise가 나중에 완료되면 결과를 받을 수 있습니다.
상태 변화
- Pending (대기): Promise가 실행되는 동안.
- Fulfilled (이행): 비동기 작업이 성공적으로 끝난 경우.
- Rejected (거부): 비동기 작업이 실패한 경우.
✅ 정리
- fetch: HTTP 요청을 보내고 응답을 받는 기본 함수. Promise를 반환합니다.
- await: 비동기 작업의 완료를 기다려, 동기적인 코드처럼 작성할 수 있게 해줍니다.
- 결합: await fetch를 사용하면 네트워크 요청과 응답 처리를 효율적으로 작성할 수 있습니다.
💻 fetch
: JavaScript의 내장 함수로, 브라우저에서 HTTP 요청을 보내고 응답을 처리하는 데 사용됩니다.
기본 구조
fetch(url, options)
.then(response => {
// 응답 처리
})
.catch(error => {
// 에러 처리
});
주요 특징
- HTTP 요청: REST API와 같은 엔드포인트로 요청을 보낼 때 사용됩니다. (GET, POST, PUT, DELETE 등)
- Promise 반환: fetch는 요청에 대한 Promise 객체를 반환합니다. 이를 통해 비동기적으로 응답을 처리할 수 있습니다.
- 옵션 지정 가능: 헤더, 본문 데이터, 요청 메서드 등 다양한 요청 설정이 가능합니다.
예제
fetch("<https://api.example.com/data>", {
method: "GET", // HTTP 메서드 (기본값: GET)
headers: {
"Content-Type": "application/json", // JSON 데이터 요청
},
})
.then(response => response.json()) // 응답을 JSON으로 변환
.then(data => console.log(data)) // 변환된 데이터 출력
.catch(error => console.error("Error:", error)); // 에러 처리
💻 await
: JavaScript에서 비동기 작업의 결과를 기다릴 때 사용하는 키워드입니다. 이는 주로 async 함수 내부에서 사용됩니다.
주요 특징
- Promise의 결과를 기다림: await는 비동기 작업이 완료될 때까지 코드 실행을 일시적으로 멈춥니다.
- 코드 가독성 향상: 기존 Promise의 .then() 체인을 대체하여 동기적인 코드처럼 읽히게 만듭니다.
예제
async function fetchData() {
try {
const response = await fetch("<https://api.example.com/data>"); // fetch 호출
const data = await response.json(); // 응답 데이터 처리
console.log(data); // 데이터 출력
} catch (error) {
console.error("Error:", error); // 에러 처리
}
}
fetchData();
💻 fetch와 await 결합
: fetch와 await를 함께 사용하면, 비동기 작업을 더 직관적이고 간결하게 처리할 수 있습니다.
fetch + await의 흐름
- HTTP 요청: fetch로 서버에 요청을 보냅니다.
- 응답 대기: await를 사용해 요청이 완료될 때까지 기다립니다.
- 응답 처리: 응답 데이터를 JSON으로 변환하거나, 상태 코드를 확인합니다.
예제: GET 요청
async function getData() {
try {
const response = await fetch("<https://api.example.com/data>");
if (!response.ok) { // 응답 상태 확인 (200~299 범위가 아니면 에러)
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json(); // JSON 데이터 변환
console.log(data); // 데이터 출력
} catch (error) {
console.error("Error:", error); // 에러 처리
}
}
getData();
✅ 주의사항
- fetch - 기본적으로 실패 처리 없음
: 네트워크 에러가 아니라면 fetch는 상태 코드(예: 404, 500)를 자동으로 에러로 간주하지 않습니다. 상태 코드를 수동으로 확인해야 합니다.
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
- 기본 HTTP 메서드는 GET
: POST, PUT 등을 사용하려면 명시적으로 method를 지정해야 합니다. - 옵션 추가로 헤더 설정 가능
: headers를 사용해 요청의 헤더를 커스터마이징할 수 있습니다.
반응형