Backend
[Backend] GraphQL
아몬드맛빼빼로
2024. 11. 25. 12:32
반응형
GraphQL 개요
GraphQL의 주요 특징
- 단일 엔드포인트로의 유연한 접근
GraphQL은 단일 엔드포인트(/graphql
)를 통해 모든 데이터 요청을 처리한다. REST API처럼 여러 엔드포인트를 관리해야 하는 복잡성을 줄이고, 클라이언트가 특정 데이터에 대한 요청을 자유롭게 구성할 수 있다. - 필요한 데이터만 요청 가능
GraphQL은 클라이언트가 필요한 데이터만 요청하도록 설계되었다. 불필요한 데이터를 전송받을 필요 없이 원하는 필드를 명시적으로 요청할 수 있어 네트워크 사용을 효율화할 수 있다. - 타입 시스템을 통한 데이터 일관성 보장
GraphQL 스키마는 데이터의 구조와 타입을 명확하게 정의한다. 이를 통해 개발자는 API가 어떤 데이터를 주고받는지 쉽게 이해할 수 있으며, 런타임 오류를 줄일 수 있다. - Subscription을 통한 실시간 데이터
GraphQL은Subscription
을 이용하여 실시간 데이터를 처리할 수 있다. 이는 주식 가격 변동이나 채팅 메시지와 같은 실시간 데이터 업데이트에 유용하다.
GraphQL 사용 예제
1. 데이터 조회 (Query)
특정 책 정보를 조회하는 예제이다.
query {
bookById(id: "1") {
title
author
}
}
{
"data": {
"bookById": {
"title": "GraphQL 배우기",
"author": "김명현"
}
}
}
2. 데이터 생성 (Mutation)
새로운 책을 생성하는 예제이다.
mutation {
createBook(input: { title: "GraphQL의 모든 것", author: "김철수" }) {
id
title
author
}
}
{
"data": {
"createBook": {
"id": "2",
"title": "GraphQL?",
"author": "권재헌"
}
}
}
3. 데이터 수정 (Mutation)
기존 책 정보를 수정하는 예제이다.
mutation {
updateBook(id: "2", input: { title: "GraphQL 심화 가이드" }) {
id
title
author
}
}
{
"data": {
"updateBook": {
"id": "2",
"title": "GraphQL!",
"author": "김태은"
}
}
}
4. 데이터 삭제 (Mutation)
책을 삭제하는 요청이다.
mutation {
deleteBook(id: "2")
}
{
"data": {
"deleteBook": true
}
}
REST API와 GraphQL 비교
특징 | REST API | GraphQL |
---|---|---|
엔드포인트 | 여러 개의 엔드포인트 필요 | 단일 엔드포인트 (/graphql ) |
데이터 요청 | 고정된 데이터 전송 | 필요한 데이터만 선택적 요청 가능 |
데이터 일관성 | 데이터 형식 명시적 정의 부족 | 스키마로 데이터 형식 명확하게 정의 |
불필요한 데이터 | 전체 리소스를 반환 | 필요한 필드만 반환 |
실시간 데이터 | 별도 구현 필요 | Subscription 으로 지원 |
Spring Boot와 GraphQL
Spring Boot와 GraphQL을 결합하여 사용하는 방법을 살펴보자. 이를 통해 어떻게 GraphQL을 백엔드에 통합하고 API를 구현하는지 알 수 있다.
1. 의존성 추가
Spring Boot 프로젝트에 GraphQL을 사용하려면, build.gradle
에 다음과 같은 의존성을 추가한다.
dependencies {
implementation("org.springframework.boot:spring-boot-starter-graphql")
implementation("com.graphql-java:graphql-spring-boot-starter")
}
2. GraphQL 스키마 정의
src/main/resources/graphql
폴더에 .graphqls
파일을 생성하여 스키마를 정의한다. 예를 들어 book.graphqls
파일에 다음과 같이 작성할 수 있다.
type Query {
bookById(id: ID!): Book
allBooks: [Book]
}
type Mutation {
createBook(input: CreateBookInput!): Book
updateBook(id: ID!, input: UpdateBookInput!): Book
deleteBook(id: ID!): Boolean
}
type Book {
id: ID!
title: String!
author: String!
}
input CreateBookInput {
title: String!
author: String!
}
input UpdateBookInput {
title: String
author: String
}
3. 서비스 및 리졸버 작성
GraphQL 요청을 처리하는 리졸버 클래스를 작성하여, 비즈니스 로직을 구현한다. 예를 들어 책 정보를 관리하는 서비스를 작성할 수 있다.
@Service
class BookService {
private val books = mutableListOf<Book>()
fun getBookById(id: String): Book? {
return books.find { it.id == id }
}
fun getAllBooks(): List<Book> {
return books
}
fun createBook(input: CreateBookInput): Book {
val book = Book(UUID.randomUUID().toString(), input.title, input.author)
books.add(book)
return book
}
fun updateBook(id: String, input: UpdateBookInput): Book? {
val book = books.find { it.id == id }
book?.apply {
title = input.title ?: title
author = input.author ?: author
}
return book
}
fun deleteBook(id: String): Boolean {
return books.removeIf { it.id == id }
}
}
4. 리졸버 연결
리졸버 클래스를 작성하여 GraphQL 스키마와 서비스 로직을 연결한다.
@Component
class BookResolver(private val bookService: BookService) {
@QueryMapping
fun bookById(@Argument id: String): Book? {
return bookService.getBookById(id)
}
@QueryMapping
fun allBooks(): List<Book> {
return bookService.getAllBooks()
}
@MutationMapping
fun createBook(@Argument input: CreateBookInput): Book {
return bookService.createBook(input)
}
@MutationMapping
fun updateBook(@Argument id: String, @Argument input: UpdateBookInput): Book? {
return bookService.updateBook(id, input)
}
@MutationMapping
fun deleteBook(@Argument id: String): Boolean {
return bookService.deleteBook(id)
}
}