on my way
React에서 Axios를 이용한 REST API 호출 및 비동기 프로그래밍 이해하기 본문
API 테스트
API란?
API는 애플리케이션 프로그래밍 인터페이스(Application Programming Interface)의 약자로, 프로그램이나 애플리케이션 간에 데이터를 주고받는 방법을 말해요.
쉽게 말하면, API는 두 프로그램이 서로 대화할 수 있게 해주는 통로라고 할 수 있어요.
예를 들어, 당신이 좋아하는 앱에서 날씨 정보를 보여준다고 생각해보세요.
그 앱이 직접 날씨 데이터를 수집하지 않고, 다른 날씨 서비스에서 데이터를 가져온다고 할 때, 이때 API를 통해 데이터를 가져옵니다.
라이브러리는 코드의 모음으로, 프로그램에서 특정 기능을 쉽게 사용할 수 있게 도와줘요.
예를 들어, 어떤 수학 문제를 풀어야 하는 프로그램을 만든다면, 복잡한 수학 계산을 미리 정의해둔 라이브러리를 가져와서 사용할 수 있어요.
요약하자면:
- API: 서로 다른 프로그램이 데이터를 주고받는 방법이나 규칙.
- 라이브러리: 특정 기능을 쉽게 사용할 수 있게 모아둔 코드의 모음.
API는 프로그램들이 서로 데이터를 주고받게 해주고, 라이브러리는 프로그램에 필요한 기능을 쉽게 사용할 수 있게 도와줘요.
Axios란?
Axios는 HTTP 요청을 보낼 때 사용하는 JavaScript 라이브러리입니다.
Axios를 사용하면 GET, POST, PUT, DELETE 요청을 쉽게 보낼 수 있으며, Promise 기반으로 비동기 처리를 지원합니다.
React에서 API 호출하기
React에서는 Axios를 사용하여 API를 호출할 수 있습니다.
다음은 예시 코드입니다. 이 코드는 JSONPlaceholder라는 온라인 REST API에서 포스트 데이터를 가져옵니다.
Api1.js
import axios from "axios";
import { useState } from "react";
const Api1 = () => {
const [data, setData] = useState([]); // state 초기화
// API 호출 함수
const callApi = () => {
axios.get("https://jsonplaceholder.typicode.com/posts").then((res) => {
console.log(res);
setData(res.data);
});
};
return (
<>
<button onClick={callApi}>API 호출</button>
<div>
<ul>
<li>제목</li>
{data.map((d) => (
<li key={d.id}>{d.title}</li>
))}
</ul>
</div>
</>
);
};
export default Api1;
이 코드는 버튼을 클릭하면 callApi 함수가 실행되고, JSONPlaceholder에서 데이터를 가져와 data 상태에 저장합니다. 저장된 데이터는 리스트로 렌더링됩니다.
App.js
import logo from "./logo.svg";
import "./App.css";
import Api1 from "./Api1";
function App() {
return <Api1 />;
}
export default App;
이 코드는 Api1 컴포넌트를 불러와서 렌더링합니다.
결과적으로 버튼을 클릭하면 API를 호출하고 데이터를 화면에 표시합니다.
- F/E (Front-End):
- 사용자 인터페이스가 있는 부분으로, React와 같은 프론트엔드 라이브러리를 사용합니다.
- 이곳에서 사용자가 어떤 행동(예: 버튼 클릭)을 하면 API 요청을 보냅니다.
- B/E (Back-End):
- 서버에서 데이터를 처리하고 응답을 돌려주는 부분입니다.
- API 서버가 이 역할을 담당하며, 데이터베이스와의 연동도 여기서 이루어집니다.
- Axios 요청:
- React에서 Axios를 사용해 API 서버로 GET, POST 등의 요청을 보냅니다.
- API 응답:
- 서버에서 JSON 형식으로 데이터를 응답합니다.
- 비동기 처리:
- Axios는 비동기적으로 데이터를 받아오며, 데이터를 받은 후 React의 state를 업데이트하여 화면에 렌더링합니다.
이렇게 프론트엔드와 백엔드가 API를 통해 상호작용하며, 사용자는 웹 애플리케이션을 통해 데이터를 확인할 수 있습니다.
REST API란?
REST API(Representational State Transfer Application Programming Interface)는 웹 서비스를 만들기 위한 아키텍처 스타일입니다.
REST는 간단하고 직관적인 설계 원칙을 따르며, 웹에서 데이터를 요청하고 처리하는 데 사용됩니다.
REST API는 다음과 같은 특징이 있습니다:
- 자원(Resource) 기반: 모든 데이터는 자원(resource)으로 간주되며, 각 자원은 고유한 URI(Uniform Resource Identifier)로 식별됩니다.
- 표현(Representation): 클라이언트는 서버의 자원을 요청하고, 서버는 요청된 자원의 표현을 클라이언트에 보냅니다. 이 표현은 주로 JSON이나 XML 형식입니다.
- HTTP 메서드 사용: REST API는 HTTP 메서드를 사용하여 자원에 대한 작업을 수행합니다. 주로 사용되는 메서드는 다음과 같습니다:
- GET: 자원 조회
- POST: 자원 생성
- PUT: 자원 전체 수정
- PATCH: 자원 부분 수정
- DELETE: 자원 삭제
- 무상태성(Stateless): 각 요청은 독립적이며, 서버는 이전 요청에 대한 정보를 저장하지 않습니다. 클라이언트는 필요한 모든 정보를 각 요청에 포함시켜야 합니다.
- 캐시 가능(Cacheable): 응답은 캐시될 수 있어야 합니다. 이를 통해 성능을 향상시킬 수 있습니다.
예제 코드로 이해하기
REST API 예제
import axios from 'axios';
// GET 요청으로 모든 게시물 가져오기
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log('모든 게시물:', response.data);
})
.catch(error => {
console.error('에러 발생:', error);
});
// POST 요청으로 새로운 게시물 생성하기
axios.post('https://jsonplaceholder.typicode.com/posts', {
title: '새 게시물',
body: '게시물 내용',
userId: 1
})
.then(response => {
console.log('새로운 게시물 생성:', response.data);
})
.catch(error => {
console.error('에러 발생:', error);
});
비동기 처리 예제
import axios from 'axios';
import { useState } from 'react';
const ApiExample = () => {
const [data, setData] = useState([]); // state 초기화
// API 호출 함수
const callApi = async () => {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
setData(response.data);
} catch (error) {
console.error('API 호출 중 에러 발생:', error);
}
};
return (
<>
<button onClick={callApi}>API 호출</button>
<div>
<ul>
{data.map((d) => (
<li key={d.id}>{d.title}</li>
))}
</ul>
</div>
</>
);
};
export default ApiExample;
이 예제에서는 비동기 함수 callApi를 통해 API를 호출하고, 그 결과를 data 상태에 저장합니다.
버튼을 클릭하면 callApi 함수가 실행되고, API로부터 데이터를 받아와 화면에 렌더링합니다.
비동기 처리와 REST API를 이해하고 나면, 웹 개발에서 데이터를 효율적으로 주고받는 방법을 더 잘 이해할 수 있습니다.
이를 통해 사용자에게 더 나은 경험을 제공할 수 있습니다.
RESTful API와 REST API는 매우 밀접한 관계가 있지만, 엄밀히 따지면 다소 차이가 있습니다.
아래에서 두 개념을 명확히 설명하겠습니다.
REST API
REST API는 Representational State Transfer (REST) 원칙을 기반으로 한 API입니다.
REST는 웹 서비스를 설계하는 아키텍처 스타일로, 2000년 로이 필딩(Roy Fielding)의 박사 논문에서 처음 제안되었습니다. REST의 주요 원칙은 다음과 같습니다:
- 자원(Resource) 기반: URI를 통해 자원을 식별합니다.
- 표현(Representation): 클라이언트는 자원의 상태를 요청하고, 서버는 자원의 표현을 클라이언트에 보냅니다. 일반적으로 JSON 또는 XML 형식을 사용합니다.
- HTTP 메서드 사용: 자원에 대한 작업은 HTTP 메서드를 통해 수행합니다. 주요 메서드는 GET, POST, PUT, DELETE 등이 있습니다.
- 무상태성(Stateless): 각 요청은 독립적이며, 서버는 요청 간의 상태를 저장하지 않습니다.
- 캐시 가능(Cacheable): 응답은 캐시될 수 있어야 합니다.
- 계층 구조(Layered System): 클라이언트는 여러 계층의 서버와 상호 작용할 수 있습니다.
RESTful API
RESTful API는 REST 아키텍처 원칙을 준수하여 설계된 API입니다.
"RESTful"이라는 용어는 REST 원칙을 잘 따르고 있는지를 나타냅니다.
즉, RESTful API는 REST의 제약 조건과 원칙을 따르는 API를 말합니다.
차이점 요약
- REST API: REST 아키텍처 원칙을 기반으로 하는 모든 API를 의미합니다.
- RESTful API: REST 아키텍처 원칙을 충실히 따르는 API를 의미합니다.
따라서 모든 RESTful API는 REST API이지만, 모든 REST API가 RESTful API는 아닐 수 있습니다.
RESTful API는 REST 원칙을 엄격히 따르는 반면, REST API는 이러한 원칙을 완전히 준수하지 않을 수 있습니다.
예제
RESTful API와 REST API의 차이를 예제로 설명해 보겠습니다.
RESTful API 예제
- GET 요청: GET /users/123
- 특정 사용자의 정보를 조회합니다.
- 클라이언트는 /users/123 URI를 통해 사용자 자원을 식별합니다.
- POST 요청: POST /users
- 새로운 사용자를 생성합니다.
- 클라이언트는 /users URI를 통해 사용자 자원을 식별하고, 요청 본문에 새 사용자 데이터를 포함합니다.
REST API 예제 (비 RESTful)
- GET 요청: GET /getUser?id=123
- 특정 사용자의 정보를 조회합니다.
- URI에 자원의 상태를 표현하지 않고, 쿼리 파라미터를 사용합니다.
- POST 요청: POST /createUser
- 새로운 사용자를 생성합니다.
- URI가 동사(createUser)로 되어 있어 RESTful 원칙을 위반합니다.
요약
RESTful API는 REST 원칙을 철저히 따르는 API이고, REST API는 그 원칙을 기반으로 하지만 반드시 엄격히 따르지는 않을 수 있습니다. 이 차이를 이해하면 더 나은 API 설계를 할 수 있습니다.
비동기(Asynchronous)란?
비동기 처리란 어떤 작업이 완료될 때까지 기다리지 않고, 다음 작업을 먼저 수행하는 방식입니다.
웹 개발에서는 주로 서버에 요청을 보내고 응답을 기다릴 때 사용됩니다.
비동기 처리를 통해 사용자는 페이지가 멈추지 않고, 다른 작업을 계속할 수 있습니다.
예를 들어, 웹 페이지에서 데이터를 서버로 요청하는 동안 사용자는 다른 버튼을 클릭하거나 페이지를 스크롤할 수 있습니다.
비동기를 왜 사용하나요?
비동기(asynchronous) 처리는 웹 개발에서 중요한 역할을 합니다. 그 이유는 다음과 같습니다:
- 사용자 경험 향상:
- 비동기 처리를 사용하면 페이지를 새로 고침하지 않고도 데이터를 주고받을 수 있습니다. 이는 사용자 경험을 크게 향상시킵니다. 예를 들어, 사용자가 게시물을 작성하고 서버에 저장할 때, 페이지를 새로 고침하지 않고도 저장 결과를 즉시 확인할 수 있습니다.
- 성능 향상:
- 비동기 처리는 요청을 보내고 응답을 기다리는 동안 다른 작업을 계속할 수 있게 합니다. 이를 통해 애플리케이션의 성능을 향상시킬 수 있습니다. 동기 방식으로 요청을 처리하면, 응답을 기다리는 동안 다른 작업이 블록됩니다.
- 자원 효율성:
- 비동기 처리는 서버 자원을 효율적으로 사용할 수 있게 합니다. 서버는 클라이언트의 요청을 비동기적으로 처리하여 더 많은 요청을 동시에 처리할 수 있습니다.
- 코드 가독성 및 유지보수성 향상:
- 비동기 코드를 작성하면, 비동기 작업의 완료 시점을 명확하게 할 수 있어 코드의 가독성과 유지보수성이 향상됩니다. Promise나 async/await 같은 비동기 처리 방법은 비동기 작업을 더 쉽게 관리할 수 있게 합니다.
Promise란?
Promise는 자바스크립트에서 비동기 작업을 처리하는 방법 중 하나입니다. Promise는 다음 세 가지 상태를 가집니다:
- 대기(Pending): 비동기 작업이 아직 완료되지 않은 상태.
- 이행(Fulfilled): 비동기 작업이 성공적으로 완료된 상태.
- 거부(Rejected): 비동기 작업이 실패한 상태.
Promise 객체는 .then(), .catch(), .finally() 메서드를 사용하여 비동기 작업의 결과를 처리합니다.
.then(), .catch(), .finally()
Promise가 이행되면 .then(),
거부되면 .catch(),
작업이 완료되면 (성공 여부와 관계없이) .finally()가 호출됩니다.
// 예제: Promise와 then, catch, finally 사용하기
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 비동기 작업
const success = true;
if (success) {
resolve("데이터를 성공적으로 가져왔습니다!");
} else {
reject("데이터를 가져오지 못했습니다.");
}
}, 1000);
});
};
fetchData()
.then((data) => {
console.log(data); // "데이터를 성공적으로 가져왔습니다!" 출력
})
.catch((error) => {
console.error(error); // 오류 메시지 출력
})
.finally(() => {
console.log("작업이 완료되었습니다."); // 작업 완료 메시지 출력
});
async/await
JavaScript에서는 비동기 작업을 처리하는 데 여러 가지 방법이 있습니다.
그 중 대표적인 방법이 .then(), .catch(), .finally() 체인을 사용하는 방법과 async/await 문법을 사용하는 방법입니다.
두 방법 모두 비동기 코드를 더 읽기 쉽고 관리하기 쉽게 만들어 줍니다.
async/await는 ES2017 (ES8)에서 도입된 새로운 문법으로, Promise 기반의 코드를 보다 읽기 쉽고 동기 코드처럼 작성할 수 있게 해줍니다.
- async 함수는 항상 Promise를 반환합니다.
- await 키워드는 Promise가 이행될 때까지 기다립니다.
// 예제: async/await 사용하기
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("데이터를 성공적으로 가져왔습니다!");
} else {
reject("데이터를 가져오지 못했습니다.");
}
}, 1000);
});
};
const getData = async () => {
try {
const data = await fetchData(); // Promise가 이행될 때까지 기다림
console.log(data); // "데이터를 성공적으로 가져왔습니다!" 출력
} catch (error) {
console.error(error); // 오류 메시지 출력
} finally {
console.log("작업이 완료되었습니다."); // 작업 완료 메시지 출력
}
};
getData();
설명
- fetchData 함수는 1초 후에 데이터를 성공적으로 가져오거나 오류를 발생시키는 Promise를 반환합니다.
- getData 함수는 async 키워드로 정의되며, 이 함수 내부에서 await 키워드를 사용하여 fetchData가 완료될 때까지 기다립니다.
- await fetchData()는 fetchData가 성공적으로 완료되면 반환된 데이터를 data 변수에 저장하고, 실패하면 catch 블록으로 넘어갑니다.
- try 블록 안에서 await fetchData()를 호출하면 Promise가 성공적으로 이행될 때까지 기다린 후, 그 결과를 data 변수에 할당합니다.
- catch 블록에서는 fetchData가 실패할 경우 오류 메시지를 출력합니다.
- finally 블록은 Promise의 성공 여부와 관계없이 항상 실행되어 "작업이 완료되었습니다."라는 메시지를 출력합니다.
await의 특징
- 비동기 함수 내부에서만 사용 가능: await는 async 함수 내부에서만 사용할 수 있습니다.
- Promise 반환: await는 Promise가 완료될 때까지 기다리며, Promise가 성공적으로 완료되면 그 결과 값을 반환하고, 실패하면 오류를 발생시킵니다.
- 코드 가독성 향상: await를 사용하면 비동기 코드를 마치 동기 코드처럼 작성할 수 있어 가독성이 크게 향상됩니다.
이처럼 await를 사용하면 비동기 작업을 보다 직관적이고 읽기 쉽게 작성할 수 있습니다.
요약
- .then(), .catch(), .finally(): Promise 객체의 메서드로, 비동기 작업이 이행, 거부, 완료될 때 각각 호출됩니다.
- async/await: 비동기 함수를 작성할 때 Promise 기반의 코드를 동기 코드처럼 읽기 쉽게 만들어 주는 문법입니다.
두 방법 모두 비동기 코드를 더 효율적이고 관리하기 쉽게 만들어 주지만, async/await는 특히 비동기 작업이 많거나 중첩된 경우에 코드의 가독성을 크게 향상시킵니다.
HTTP GET 요청이란?
GET 요청은 서버로부터 데이터를 요청하는 방법입니다. 주로 데이터를 조회할 때 사용됩니다. 예를 들어, 사용자가 게시물 목록을 보고자 할 때 GET 요청을 보냅니다.
예제:
axios.get("https://jsonplaceholder.typicode.com/posts")
.then((response) => {
console.log(response.data); // 서버로부터 받은 데이터
})
.catch((error) => {
console.error("에러 발생:", error);
});
HTTP POST 요청이란?
POST 요청은 서버로 데이터를 전송하는 방법입니다. 주로 데이터를 생성하거나 업데이트할 때 사용됩니다. 예를 들어, 사용자가 새로운 게시물을 작성할 때 POST 요청을 보냅니다.
예제:
axios.post("https://jsonplaceholder.typicode.com/posts", {
title: '새 게시물',
body: '게시물 내용',
userId: 1
})
.then((response) => {
console.log(response.data); // 서버로부터 받은 응답 데이터
})
.catch((error) => {
console.error("에러 발생:", error);
});
CORS와 @CrossOrigin
CORS(Cross-Origin Resource Sharing)는 웹 브라우저가 서로 다른 도메인에서 자원을 요청할 때 발생하는 문제를 해결하기 위한 보안 기능입니다. 예를 들어, 우리가 http://localhost:3000에서 실행 중인 React 애플리케이션이 http://localhost:8080의 서버 API를 호출할 때, CORS 정책에 의해 차단될 수 있습니다.
Spring Boot에서 이러한 문제를 해결하기 위해 @CrossOrigin 어노테이션을 사용합니다.
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/api/data")
public List<String> getData() {
return List.of("Data 1", "Data 2", "Data 3");
}
}
이 코드는 React 애플리케이션에서 http://localhost:3000에서 오는 API 요청을 허용합니다. 만약 @CrossOrigin을 사용하지 않으면, Axios로 요청을 보낼 때 CORS 정책에 의해 에러가 발생합니다.
Spring Initializr란?
Spring Initializr는 Spring Boot 프로젝트를 쉽게 생성할 수 있도록 도와주는 웹 도구입니다. Spring Initializr를 사용하면 필요한 종속성을 선택하고, 프로젝트 설정을 구성한 후, 프로젝트를 다운로드하여 바로 개발을 시작할 수 있습니다.
Spring Initializr 사용 방법:
- Spring Initializr 웹사이트에 접속합니다.
- 프로젝트 메타데이터(이름, 그룹, 아티팩트, 설명 등)를 입력합니다.
- 종속성(Dependencies)을 선택합니다. 예를 들어, Spring Web, Spring Data JPA 등.
- Generate 버튼을 클릭하여 프로젝트를 다운로드합니다.
- 다운로드한 프로젝트를 IDE에서 열고 개발을 시작합니다.
이제 API 테스트를 위한 기본적인 개념과 사용 방법을 알게 되었습니다. React와 Spring Boot를 연동하여 더 강력한 웹 애플리케이션을 개발할 수 있습니다.
'Computer Science > React' 카테고리의 다른 글
CORS란? 필요성, 작동 방식 및 어노테이션 예제 (0) | 2024.08.06 |
---|---|
한 입 크기로 잘라먹는 리액트 9장: 컴포넌트 트리에 데이터 공급 (0) | 2024.07.16 |
한 입 크기로 잘라먹는 리액트 8장: 최적화 (2) | 2024.07.16 |
한 입 크기로 잘라먹는 리액트 Project2: [할 일 관리] 앱 만들기 + 업데이트 (0) | 2024.07.16 |
한 입 크기로 잘라먹는 리액트 Project1: [카운터] 앱 만들기 (1) | 2024.07.16 |