Python Graphene 및 Strawberry를 이용한 견고한 GraphQL API 구축
Daniel Hayes
Full-Stack Engineer · Leapcell

소개: API 디자인의 진화
백엔드 개발의 광대한 환경에서 API는 서로 다른 소프트웨어 구성 요소 간의 중요한 통신 브릿지 역할을 합니다. 전통적으로 RESTful API는 이 공간을 지배하며 잘 이해되고 널리 채택된 아키텍처 스타일을 제공했습니다. 그러나 애플리케이션이 점점 더 복잡해지고 데이터에 대한 갈증이 심해짐에 따라 과도한 데이터 가져오기 또는 부족한 데이터 가져오기, 여러 왕복 통신의 필요성과 같은 REST의 한계가 명백해졌습니다. 바로 여기서 GraphQL이 등장하여 더 효율적이고 유연하며 강력한 대안을 제공합니다. GraphQL을 통해 클라이언트는 필요한 데이터를 정확하게 정의할 수 있으므로 단일 API 엔드포인트로도 다양한 클라이언트 요구 사항을 충족할 수 있습니다.
Python 개발자에게 Graphene-Django와 Strawberry라는 두 가지 주요 라이브러리가 강력한 GraphQL API 구축을 위한 훌륭한 선택지로 부상했습니다. 이 글에서는 이러한 강력한 도구들을 살펴보고, 핵심 개념, 실용적인 구현, 그리고 이들이 뛰어난 시나리오를 분석하여 궁극적으로 더 좋고 효율적인 API 구축을 안내할 것입니다.
GraphQL의 핵심 원리 이해
Graphene-Django 및 Strawberry의 세부 사항을 자세히 알아보기 전에 GraphQL의 핵심 개념에 대한 기초적인 이해를 확립해 봅시다. 이러한 용어는 모든 GraphQL API를 설계하고 상호 작용하는 데 기본이 됩니다.
스키마 정의 언어(SDL)
GraphQL은 스키마 정의 언어(SDL)를 사용하여 정의된 강력한 유형 시스템에 의존합니다. SDL은 사용 가능한 데이터, 해당 유형, 관계, 그리고 수행할 수 있는 작업(쿼리, 뮤테이션, 구독)을 설명합니다. 이는 클라이언트와 서버 간의 계약 역할을 하며 데이터 무결성과 예측 가능한 응답을 보장합니다.
데이터 가져오기를 위한 쿼리
쿼리는 클라이언트가 GraphQL 서버에서 데이터를 요청하는 방식입니다. 클라이언트가 고정된 리소스에 액세스하는 REST와 달리 GraphQL 쿼리를 통해 클라이언트는 필요한 필드와 중첩된 관계를 정확히 지정하여 데이터 가져오기 또는 가져오기 실패를 최소화할 수 있습니다.
데이터 조작을 위한 뮤테이션
뮤테이션은 서버에서 데이터를 수정하는 데 사용됩니다. 쿼리와 유사하게 뮤테이션도 잘 정의된 구조를 가지며, 데이터 수정 후 입력 인수와 예상되는 반환 유형을 지정합니다. 이를 통해 데이터를 업데이트하는 예측 가능하고 제어된 방법을 보장합니다.
유형 및 필드
GraphQL 스키마의 핵심에는 데이터 구조를 정의하는 유형이 있습니다. 유형은 특정 데이터 유형(예: 문자열, 정수, 부울, 사용자 지정 객체 유형)을 가진 필드로 구성됩니다. 이러한 유형과 필드는 GraphQL API의 빌딩 블록입니다.
스키마를 데이터에 연결하는 리졸버
리졸버는 유형의 각 필드에 대한 실제 데이터를 가져오는 역할을 하는 함수입니다. GraphQL 쿼리가 도착하면 서버는 스키마를 순회하며 요청된 각 필드에 대해 적절한 리졸버를 호출하여 백엔드(예: 데이터베이스, 다른 API 또는 메모리 내 데이터 저장소)에서 해당 데이터를 검색합니다.
구조화된 인수를 위한 입력 객체
입력 객체는 뮤테이션 또는 복잡한 쿼리의 인수로 사용되는 특수 객체 유형입니다. 클라이언트는 구조화된 데이터를 단일 인수로 전달할 수 있어 API 호출을 더 깔끔하고 체계적으로 만들 수 있습니다.
Graphene-Django 및 Strawberry를 통한 GraphQL API 구축
이제 기본 GraphQL 개념을 파악했으므로 Graphene-Django 및 Strawberry가 Python 프레임워크와 통합되어 강력한 GraphQL API를 구축하는 방법을 살펴보겠습니다.
Django 프로젝트를 위한 Graphene-Django
Graphene-Django는 Django 애플리케이션에 GraphQL을 원활하게 통합합니다. Django의 ORM 및 모델 시스템을 활용하여 GraphQL 스키마의 많은 부분을 자동으로 생성하므로 상용구 코드를 크게 줄일 수 있습니다.
Graphene-Django 설정
먼저 Graphene-Django를 설치합니다.
pip install graphene-django
settings.py
에서 INSTALLED_APPS
에 graphene_django
를 추가합니다.
# settings.py INSTALLED_APPS = [ # ... 'graphene_django', ]
앱 내의 schema.py
파일에 GraphQL 스키마를 정의합니다.
# myapp/schema.py import graphene from graphene_django.types import DjangoObjectType from .models import Author, Book class AuthorType(DjangoObjectType): class Meta: model = Author fields = ('id', 'name', 'books') class BookType(DjangoObjectType): class Meta: model = Book fields = ('id', 'title', 'published_date', 'author') class Query(graphene.ObjectType): all_authors = graphene.List(AuthorType) author_by_id = graphene.Field(AuthorType, id=graphene.Int()) all_books = graphene.List(BookType) def resolve_all_authors(root, info): return Author.objects.all() def resolve_author_by_id(root, info, id): try: return Author.objects.get(pk=id) except Author.DoesNotExist: return None def resolve_all_books(root, info): return Book.objects.all() class CreateAuthor(graphene.Mutation): class Arguments: name = graphene.String(required=True) author = graphene.Field(AuthorType) @classmethod def mutate(cls, root, info, name): author = Author(name=name) author.save() return CreateAuthor(author=author) class Mutation(graphene.ObjectType): create_author = CreateAuthor.Field() schema = graphene.Schema(query=Query, mutation=Mutation)
마지막으로 urls.py
를 구성하여 GraphQL 엔드포인트를 노출합니다.
# project/urls.py from django.contrib import admin from django.urls import path from graphene_django.views import GraphQLView from myapp.schema import schema urlpatterns = [ path('admin/', admin.site.urls), path("graphql/", GraphQLView.as_view(graphiql=True, schema=schema)), ]
이 설정은 /graphql
엔드포인트를 제공하며, 종종 GraphiQL(GraphQL용 브라우저 내 IDE)이 활성화되어 API 탐색 및 테스트를 용이하게 합니다.
Graphene-Django 애플리케이션
Graphene-Django는 기존 Django 프로젝트에 GraphQL API를 노출해야 하는 경우에 이상적입니다. Django 모델 및 ORM과의 강력한 통합은 Django 모델에서 스키마 생성을 단순화하여 수동 스키마 정의를 최소화합니다. 단일 페이지 애플리케이션(SPA) 또는 데이터 가져오기에 대한 세분화된 제어가 필요한 모바일 백엔드를 구축하는 데 훌륭합니다.
FastAPI 및 Flask를 위한 Strawberry
Strawberry는 Python에서 GraphQL API를 구축하기 위한 현대적이고 타입 힌트 친화적인 접근 방식을 제공합니다. FastAPI와 같은 고성능 프레임워크에서 뛰어나며 Flask와도 통합될 수 있습니다. Python 타입 힌트를 사용하면 스키마가 명시적이어서 개발 시점에 오류를 잡는 데 도움이 됩니다.
FastAPI와 Strawberry 설정
먼저 Strawberry와 FastAPI를 설치합니다.
pip install strawberry-graphql "fastapi[all]" uvicorn
main.py
파일에 Strawberry 스키마를 정의합니다.
# main.py import datetime import strawberry from fastapi import FastAPI from typing import List, Optional @strawberry.type class Author: id: int name: str books: List["Book"] @strawberry.type class Book: id: int title: str published_date: datetime.date author: Author # 시연을 위한 메모리 내 데이터 저장소 authors_db = { 1: Author(id=1, name="Jane Doe", books=[]), 2: Author(id=2, name="John Smith", books=[]), } books_db = { 101: Book(id=101, title="The First Book", published_date=datetime.date(2020, 1, 1), author=authors_db[1]), 102: Book(id=102, title="Another Story", published_date=datetime.date(2021, 5, 10), author=authors_db[1]), 103: Book(id=103, title="Code Magic", published_date=datetime.date(2022, 3, 15), author=authors_db[2]), } # 관계 업데이트 authors_db[1].books.extend([books_db[101], books_db[102]]) authors_db[2].books.append(books_db[103]) @strawberry.type class Query: @strawberry.field def hello(self) -> str: return "Hello World" @strawberry.field def all_authors(self) -> List[Author]: return list(authors_db.values()) @strawberry.field def author_by_id(self, id: int) -> Optional[Author]: return authors_db.get(id) @strawberry.field def all_books(self) -> List[Book]: return list(books_db.values()) @strawberry.field def total_books(self) -> int: return len(books_db) @strawberry.type class CreateAuthorInput: name: str @strawberry.type class Mutation: @strawberry.mutation def create_author(self, author_input: CreateAuthorInput) -> Author: new_id = max(authors_db.keys()) + 1 if authors_db else 1 new_author = Author(id=new_id, name=author_input.name, books=[]) authors_db[new_id] = new_author return new_author schema = strawberry.Schema(query=Query, mutation=Mutation) app = FastAPI() app.add_route("/graphql", strawberry.asgi.GraphQL(schema, graphiql=True))
FastAPI 애플리케이션을 실행합니다.
uvicorn main:app --reload
그러면 일반적으로 http://127.0.0.1:8000/graphql
에서 서버가 시작되며, 여기서 GraphiQL을 통해 GraphQL 엔드포인트에 액세스할 수 있습니다.
Strawberry 애플리케이션
Strawberry는 특히 FastAPI 및 Flask와 같은 최신 Python 기능을 활용하는 새 프로젝트에 훌륭한 선택입니다. 프레임워크에 구애받지 않는 코어는 FastAPI 및 Flask를 넘어 다양한 ASGI/WSGI 프레임워크와 통합할 수 있습니다. 명시적인 스키마 정의와 타입 안전성이 높은 우선 순위인 마이크로서비스 또는 애플리케이션에 특히 적합합니다.
장단점 및 고려 사항
Graphene-Django와 Strawberry 모두 Python에서 GraphQL API를 구축하기 위한 강력한 솔루션을 제공하지만, 약간 다른 요구에 부합합니다.
- Django 통합: Graphene-Django는 Django ORM과의 긴밀한 통합을 제공하여 기존 Django 애플리케이션에 자연스럽게 맞습니다. Django 모델에서 스키마 생성을 단순화합니다.
- 타입 힌팅 및 최신 Python: Strawberry는 타입 힌트와 같은 최신 Python 기능을 채택하여 더 읽기 쉽고 유지 관리하기 쉬운 코드와 더 나은 IDE 지원을 제공합니다.
- 프레임워크에 구애받지 않음: Strawberry는 프레임워크에 더 구애받지 않아 FastAPI, Flask 및 기타 ASGI/WSGI 프레임워크와 쉽게 통합됩니다. Graphene도 다른 프레임워크와 통합될 수 있지만, Django와의 시너지가 가장 강력합니다.
- 상용구 코드: Django 모델과 직접 작업할 때 자동 필드 생성으로 인해 Graphene-Django는 상용구 코드가 적다고 느껴질 수 있습니다. Strawberry는 명시적이지만 더 큰 스키마의 경우 약간 더 많은 수동 연결이 필요할 수 있지만, 이러한 명확성은 종종 명확성과 유지 관리성 면에서 보상됩니다.
- 성능: 매우 높은 성능 시나리오의 경우 FastAPI와 Strawberry를 사용하면 FastAPI의 비동기 특성과 효율적인 요청 처리로 인해 이점을 얻을 수 있습니다.
궁극적으로 Graphene-Django와 Strawberry 간의 선택은 기존 프로젝트 스택과 아키텍처 기본 설정에 따라 달라지는 경우가 많습니다. Django에 익숙하다면 Graphene-Django는 직관적인 선택입니다. FastAPI를 사용하여 새 서비스를 구축하거나 명시적인 타입 정의를 우선시하는 경우 Strawberry가 더 나은 선택일 수 있습니다.
결론: 데이터 상호 작용의 미래 형성
Graphene-Django 또는 Strawberry를 사용하여 GraphQL API를 구축하면 개발자는 애플리케이션을 위한 효율적이고 유연하며 강력한 데이터 액세스 계층을 만들 수 있습니다. GraphQL의 원칙을 수용하고 이러한 Python 라이브러리의 강점을 활용함으로써 클라이언트는 데이터 요구 사항에 대한 탁월한 제어를 제공하여 개발 주기 단축과 사용자 경험 개선으로 이어질 수 있습니다.
기존 Django 모놀리스를 확장하든 최첨단 FastAPI 마이크로서비스를 만들든 Python의 GraphQL 생태계는 내일을 위한 API를 구축하기 위한 정교한 도구를 제공합니다. 이러한 라이브러리는 API 개발의 복잡한 작업을 단순화하여 클라이언트와 개발자 모두에게 데이터 상호 작용을 더 직관적이고 강력하게 만듭니다.