정답: Yes
GraphQL은 페이스북이 개발한 데이터 쿼리 언어로 REST API의 대안책을 찾아보다가 발견하게 되었다. REST API만 사용해봤는데 GraphQL이 더 성능이 좋다고 해서 포스팅해보려고 한다🙂
👉RESTful API는 데이터를 가져오려면 여러 요청을 보내 필요 이상의 데이터를 가져오는 문제가 있는데 GraphQL은 한번 요청해서 필요한 데이터만 가지고 올 수 있다고 함

1️⃣ GraphQL이란?
- GraphQL(Graph Query Language)은 API를 위한 쿼리 언어이자 실행 환경
- SQL이 데이터베이스를 조회하는 쿼리 언어라면 GraphQL은 API를 위한 쿼리 언어
- GraphQL의 핵심 개념
- 클라이언트가 원하는 데이터만 요청하고 받을 수 있음 (Over-fetching & Under-fetching 해결)
- 하나의 엔드포인트(/graphql)에서 모든 데이터를 제공
- 타입 시스템(Type System)을 기반으로 동작하여, API 문서를 자동으로 생성 가능
2️⃣ GraphQL과 REST API 비교
| 비교 | REST API | GraphQL |
| 데이터 요청 방식 | 여러 개의 엔드포인트에서 데이터를 가져와야 함 (/users, /posts 등) | 하나의 엔드포인트에서 필요한 데이터만 요청 |
| Over-fetching | 필요한 데이터보다 더 많은 데이터를 가져올 수 있음 | 필요한 데이터만 가져올 수 있음 |
| Under-fetching | 필요한 데이터를 다 가져오려면 여러 번 요청해야 함 | 한 번의 요청으로 필요한 데이터를 가져올 수 있음 |
| 버전 관리 | URL이나 헤더를 이용해 API 버전 관리 (/v1/users) | API 자체가 버전을 필요로 하지 않음 |
| Self-documenting | 문서화를 별도로 해야 함 (Swagger, Postman 등) | 스키마를 통해 자동으로 문서화됨 |
3️⃣ GraphQL 기본 개념
(1) Schema (스키마)
GraphQL은 타입 시스템을 기반으로 동작함. 스키마는 API가 제공하는 데이터 구조를 정의하는 역할을 한다.
type User {
id: ID!
name: String!
email: String!
}
- 여기서 User 타입은 id, name, email 필드를 포함하고, !는 필수 값임을 의미.
(2) Query (데이터 조회)
REST에서는 GET /users/1 이런 식으로 요청하지만, GraphQL에서는 원하는 필드만 선택해서 요청할 수 있음.
query {
user(id: 1) {
name
email
}
}
- 이렇게 하면 id: 1인 유저의 name과 email만 받아옴.
(3) Mutation (데이터 변경)
GraphQL에서는 데이터를 추가(Create), 수정(Update), 삭제(Delete)할 때 Mutation을 사용함.
mutation {
createUser(name: "Alice", email: "alice@example.com") {
id
name
email
}
}
- 이렇게 하면 새로운 유저를 생성하고, id, name, email을 반환함.
(4) Resolver (실제 데이터 처리 로직)
GraphQL의 Query나 Mutation 요청이 들어오면, 이를 처리하는 함수가 필요함. 이걸 Resolver라고 부름.
const resolvers = {
Query: {
user: (parent, args, context, info) => {
return users.find(user => user.id === args.id);
},
},
Mutation: {
createUser: (parent, args) => {
const newUser = { id: users.length + 1, ...args };
users.push(newUser);
return newUser;
},
},
};
- Query.user → 특정 유저 데이터를 가져옴
- Mutation.createUser → 새로운 유저를 추가함
4️⃣ GraphQL 예제
> Node.js + Express + Apollo Server
Step 1. 프로젝트 초기화
mkdir graphql-example
cd graphql-example
npm init -y
Step 2. GraphQL 및 필요한 패키지 설치
npm install express apollo-server-express graphql
Step 3. 서버 코드 작성 (index.js)
const { ApolloServer, gql } = require("apollo-server-express");
const express = require("express");
// 데이터 (DB 대신 메모리 배열 사용)
const users = [
{ id: "1", name: "Alice", email: "alice@example.com" },
{ id: "2", name: "Bob", email: "bob@example.com" },
];
// GraphQL 스키마 정의
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User!
}
`;
// Resolver 정의
const resolvers = {
Query: {
users: () => users,
user: (_, { id }) => users.find(user => user.id === id),
},
Mutation: {
createUser: (_, { name, email }) => {
const newUser = { id: String(users.length + 1), name, email };
users.push(newUser);
return newUser;
},
},
};
// Express + Apollo Server 설정
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.start().then(() => {
server.applyMiddleware({ app });
app.listen(4000, () => console.log("🚀 서버 실행 중: http://localhost:4000/graphql"));
});
Step 4. 서버 실행
node index.js
- 브라우저에서 http://localhost:4000/graphql에 접속하면 GraphQL Playground가 실행됨
> React + Spring Boot
🚩구성 요소
- Spring Boot → GraphQL API 서버
- React (Apollo Client) → 프론트엔드에서 GraphQL 요청
1. Spring Boot로 GraphQL 서버 만들기
Spring Boot에서 Spring for GraphQL 라이브러리를 사용해서 GraphQL API를 만든다.
1️⃣ 프로젝트 설정
Spring Boot 프로젝트를 생성하고, pom.xml에 GraphQL 관련 의존성을 추가.
pom.xml
<dependencies>
<!-- Spring Boot 기본 웹 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- GraphQL -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<!-- H2 Database (테스트용) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
2️⃣ 엔티티 생성 (User.java)
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// 기본 생성자 및 Getter, Setter
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
}
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
3️⃣ Repository 생성 (UserRepository.java)
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {}
4️⃣ GraphQL 서비스 및 데이터 처리 (UserService.java)
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User createUser(String name, String email) {
return userRepository.save(new User(name, email));
}
}
5️⃣ GraphQL 컨트롤러 (UserGraphQLController.java)
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import java.util.List;
@Controller
public class UserGraphQLController {
private final UserService userService;
public UserGraphQLController(UserService userService) {
this.userService = userService;
}
@QueryMapping
public List<User> users() {
return userService.getAllUsers();
}
@QueryMapping
public User user(@Argument Long id) {
return userService.getUserById(id);
}
@MutationMapping
public User createUser(@Argument String name, @Argument String email) {
return userService.createUser(name, email);
}
}
6️⃣ GraphQL 스키마 정의 (schema.graphqls)
src/main/resources/graphql/ 폴더를 만들고 schema.graphqls 파일을 추가
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User!
}
7️⃣ 서버 실행
이제 Spring Boot 서버를 실행하면 http://localhost:8080/graphql에서 GraphQL API를 사용할 수 있따.
테스트는 GraphiQL 같은 툴에서 하면 됨.
2. React (Apollo Client)로 GraphQL 연동
React에서는 Apollo Client를 사용해서 GraphQL 서버와 통신한다.
1️⃣ React 프로젝트 생성
npx create-react-app graphql-client
cd graphql-client
npm install @apollo/client graphql
2️⃣ Apollo Client 설정
src/apollo.js 파일을 만들고 Apollo Client를 설정.
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:8080/graphql',
cache: new InMemoryCache(),
});
export default client;
3️⃣ GraphQL Query 및 Mutation 작성
src/graphql.js 파일을 만들고 GraphQL 쿼리를 정의함.
import { gql } from '@apollo/client';
// 모든 사용자 조회
export const GET_USERS = gql`
query {
users {
id
name
email
}
}
`;
// 사용자 추가
export const CREATE_USER = gql`
mutation CreateUser($name: String!, $email: String!) {
createUser(name: $name, email: $email) {
id
name
email
}
}
`;
4️⃣ React 컴포넌트 작성
src/App.js 파일을 수정해서 데이터를 가져오고, 사용자 추가 기능을 구현.
import React, { useState } from 'react';
import { ApolloProvider, useQuery, useMutation } from '@apollo/client';
import client from './apollo';
import { GET_USERS, CREATE_USER } from './graphql';
const Users = () => {
const { loading, error, data } = useQuery(GET_USERS);
const [createUser] = useMutation(CREATE_USER, {
refetchQueries: [{ query: GET_USERS }],
});
const [name, setName] = useState('');
const [email, setEmail] = useState('');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>Users</h2>
<ul>
{data.users.map(user => (
<li key={user.id}>{user.name} - {user.email}</li>
))}
</ul>
<h3>Add User</h3>
<input placeholder="Name" value={name} onChange={e => setName(e.target.value)} />
<input placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} />
<button onClick={() => createUser({ variables: { name, email } })}>
Add User
</button>
</div>
);
};
const App = () => (
<ApolloProvider client={client}>
<Users />
</ApolloProvider>
);
export default App;
✅ 실행 방법
- Spring Boot 서버 실행
mvn spring-boot:run - React 클라이언트 실행
npm start
🚀 이제 브라우저에서 React 앱을 실행하면 GraphQL을 통해 Spring Boot 서버에서 데이터를 가져오고 추가할 수 있음
> React에서 Apollo Client를 사용하는 이유
1. Apollo Client의 핵심 기능
Apollo Client를 쓰면 GraphQL API와의 통신이 쉬워지고, 상태 관리도 자동으로 해줌!
✅ (1) GraphQL 요청을 간편하게 보낼 수 있음
REST API처럼 fetch를 써서 요청을 보낼 수도 있지만 GraphQL은 여러 데이터를 한 번에 요청하는 방식이기 때문에 fetch로 직접 관리하면 코드가 복잡해짐.
📌fetch로 GraphQL 요청 보내기 (비효율적인 방법)
fetch("http://localhost:8080/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query {
users {
id
name
email
}
}
`,
}),
})
.then(res => res.json())
.then(data => console.log(data))
.catch(error => console.error(error));
📌Apollo Client를 쓰면 이렇게 간단해짐
import { useQuery, gql } from "@apollo/client";
const GET_USERS = gql`
query {
users {
id
name
email
}
}
`;
const { loading, error, data } = useQuery(GET_USERS);
→ fetch보다 코드가 훨씬 깔끔하고 직관적
✅ (2) 캐싱 기능 제공 (자동 상태 관리)
GraphQL에서 같은 데이터를 여러 번 요청하면 비효율적임. Apollo Client는 캐시(cache)를 자동으로 관리해서 같은 데이터를 불필요하게 다시 요청하지 않도록 한다. 예를 들어, 유저 목록을 가져오는 쿼리를 여러 번 실행하면:
- fetch로 요청하면 매번 서버에 요청이 가야 함 (느림)
- Apollo Client는 한 번 불러온 데이터를 캐시에 저장해서 다시 요청할 필요가 없음 (빠름)
📌 캐싱 방식
const client = new ApolloClient({
uri: "http://localhost:8080/graphql",
cache: new InMemoryCache(), // 메모리 캐시 활성화
});
✅ (3) 실시간 데이터 처리 가능 (Subscription)
GraphQL에는 Subscription 기능이 있어서 서버에서 변경된 데이터를 실시간으로 받을 수 있음.
Apollo Client는 WebSocket을 사용해 이 기능을 쉽게 구현할 수 있음.
예를 들어 새로운 유저가 추가되었을 때, 기존 fetch 방식으로는 주기적으로 요청해야 하지만 Apollo Client는 Subscription을 통해 변경 사항을 자동으로 받을 수 있음.
import { useSubscription, gql } from "@apollo/client";
const USER_ADDED = gql`
subscription {
userAdded {
id
name
email
}
}
`;
const { data, loading } = useSubscription(USER_ADDED);
✅ (4) 자동으로 쿼리 리페치 (Refetching)
useQuery에 refetchQueries 옵션을 설정하면 데이터가 변경될 때 자동으로 최신 데이터를 불러올 수 있음.
예를 들어, 새로운 유저를 추가할 때 기존의 GET_USERS 데이터를 다시 불러오고 싶다면:
const [createUser] = useMutation(CREATE_USER, {
refetchQueries: [{ query: GET_USERS }],
});
→ 새 유저를 추가하면 GET_USERS 쿼리가 자동으로 다시 실행됨!
✅ (5) 다양한 상태 관리 기능
- Apollo Client는 GraphQL 상태를 쉽게 관리할 수 있는 다양한 훅을 제공
| 기능 | 훅 (Hook) |
| 데이터 가져오기 | useQuery |
| 데이터 추가/수정/삭제 | useMutation |
| 실시간 데이터 받기 | useSubscription |
➡ Redux 같은 상태 관리 라이브러리 없이도 GraphQL 데이터를 쉽게 관리 가능!
🎯 결론: Apollo Client를 써야 하는 이유
| Apollo Client 없이 | Apollo Client 사용 |
| fetch로 직접 요청, JSON 파싱 필요 | useQuery, useMutation 등 편리한 훅 제공 |
| 상태 관리 별도로 해야 함 | 캐싱 기능 자동 제공 |
| 데이터 변경 시 수동으로 업데이트 필요 | 자동으로 데이터 업데이트 가능 (refetchQueries) |
| Subscription 직접 구현해야 함 | useSubscription으로 간편하게 구현 가능 |
✅ 정리하자면
- GraphQL API와 쉽게 통신 가능
- 캐싱 & 상태 관리 자동화
- Subscription (실시간 데이터) 지원
- Redux 같은 복잡한 상태 관리 없이도 GraphQL 데이터를 효율적으로 사용 가능
➡ 그래서 React에서 GraphQL을 사용할 때는 Apollo Client가 거의 필수적으로 사용됨!
5️⃣ GraphQL 장점과 단점
✅ GraphQL 장점
- 필요한 데이터만 가져올 수 있음 (Over-fetching 방지)
- 여러 개의 요청을 하나의 요청으로 처리 가능
- 타입 기반 API라서 안정성이 높음
- Self-documenting (API 문서를 따로 만들 필요 없음)
❌ GraphQL 단점
- 설정이 복잡함 (초기 개발 비용이 높음)
- 캐싱이 어려움 (REST API의 HTTP 캐싱을 그대로 활용하기 어려움)
- 퍼포먼스 이슈 → 대량의 데이터 요청 시 성능이 떨어질 수도 있음
🎯 결론
✔️GraphQL은 REST API의 단점을 보완하여 유연하고 강력한 API 개발 방식을 제공함.
✔️단, 초기 설정이 복잡하고 캐싱이 어렵다는 단점이 있지만 데이터 요청 최적화가 필요한 프로젝트에서는 큰 장점이 될 수 있음.
'개발인생 > Backend' 카테고리의 다른 글
| [Spring] @Transactional (0) | 2025.03.19 |
|---|---|
| [Spring] Spring Data JPA (0) | 2025.03.19 |
| [Spring] Spring Boot 개발자를 위한 필수 디자인 패턴 6가지 (0) | 2025.02.25 |
| [Spring] MVC 구조 설명 | Controller, Service, Repository로 역할 분리하기 (0) | 2025.02.25 |
| [Spring] 핵심 기술 총정리 (0) | 2025.02.25 |