이전글에서 REST, gRPC 그리고 GraphQL를 비교해봤습니다. 이번에는 Python의 GraphQL 사용을 돕는 라이브러리를 비교해보려고 합니다. 솔직히 말하자면 FastAPI 유저인 저에게는 FastAPI가 공식문서에서 추천한 Strawberry가 정답으로 자리잡고 있고, 이미 Strawberry를 이용해서 구현했지만 공부하는 차원에서 각 라이브러리의 사용성, 문서화와 개발자 경험(DX), 타입 지원, 웹 프레임워크 통합성, 프로젝트 유지보수 및 커뮤니티 현황을 살펴보겠습니다.
왜 라이브러리 비교기준에서 성능이 빠졌을지 의문을 가질 수 있습니다. 하지만 물론 저도 처음에는 알아봤지만 GraphQL 서버 성능은 주로 쿼리 실행 엔진의 효율과 리졸버에서의 I/O 처리 방식에 따라 좌우되며, 세 라이브러리 모두 Python용 GraphQL 코어 라이브러리를 기반으로 하고 있어, 기본적인 쿼리 파싱/실행 성능은 큰 차이가 없다고 판단되어 비교기준에서 제외했습니다.
Python & GraphQL 라이브러리들
Python에서 GraphQL API를 구현하기 위해 많이 사용되는 라이브러리로 Strawberry, Graphene, Ariadne 세 가지가 있습니다.
- 우선 Graphene 프로젝트는 가장 역사가 오래되었지만 최근에 유지보수나 업데이트가 활발하지 않은것으로 확인되었습니다.
- Strawberry는 보다는 최근에 만들어졌으며 github에서 활발히 논의가 이뤄지는게 확인이 되었습니다.
- Ariadne 는 코드우선방식을 채택한 Graphene나 Strawberry와 다르게 스키마 우선 방식을 채택하여 비교할 가치가 있다고 생각했습니다.
각 주제별로 세 라이브러리를 비교하겠습니다.
사용성: Pythonic한 코드 작성의 간결함
GraphQL 라이브러리의 사용성은 얼마나 간결하고 Pythonic하게 스키마와 리졸버를 작성할 수 있는지를 의미합니다. 각 라이브러리는 스키마 정의 방식부터 차이가 있습니다.
Graphene
코드 우선(code-first) 접근 방식의 대표격입니다. Django ORM 스타일과 비슷하게 Python 클래스를 정의하여 GraphQL 스키마를 만듭니다. Django 개발자에게 친숙할 수 있지만, 작은 스키마에도 많은 보일러플레이트(boilerplate) 코드와 규칙이 필요할 수 있습니다.
import graphene
class User(graphene.ObjectType):
name = graphene.String()
age = graphene.Int()
class Query(graphene.ObjectType):
user = graphene.Field(User)
def resolve_user(self, info):
return User(name="Patrick", age=100)
schema = graphene.Schema(query=Query)
Strawberry
Graphene과 마찬가지로 코드 우선 접근이지만, 최신 Python 기능인 타입 힌트와 데이터클래스를 적극 활용하여 보다 간결하고 Pythonic한 인터페이스를 제공합니다.
import strawberry
@strawberry.type
class User:
name: str
age: int
@strawberry.type
class Query:
@strawberry.field
def user(self) -> User:
return User(name="Patrick", age=100)
schema = strawberry.Schema(query=Query)
Ariadne
스키마 우선(schema-first) 접근 방식을 취합니다. 즉, GraphQL의 SDL(schema definition language) 문법으로 스키마를 문자열이나 파일로 작성하고, 해당 스키마의 각 타입과 필드에 대응하는 리졸버 함수를 Python 코드로 연결합니다.
from ariadne import gql, QueryType, make_executable_schema
# GraphQL 스키마 정의 (SDL)
type_defs = gql("""
type User {
name: String!
age: Int!
}
type Query {
user: User!
}
""")
# 리졸버 객체 생성
query = QueryType()
@query.field("user")
def resolve_user(_, info):
return {"name": "Patrick", "age": 100}
schema = make_executable_schema(type_defs, query)
Ariadne을 쓰면 GraphQL 자체의 표준 문법으로 API를 명세하고, 비즈니스 로직 연결은 @query.field("fieldName") 같은 데코레이터나 ObjectType("TypeName") 객체를 통해 매핑합니다. 이 방식은 GraphQL을 잘 아는 개발자에게는 명확하고 직관적입니다.
Graphene처럼 복잡한 Python 클래스 계층을 만들 필요 없이 스키마는 스키마대로, 코드 로직은 코드대로 분리할 수 있어 단순합니다. 반면 Python 타입 힌트를 이용해 자동으로 스키마를 생성해주진 않기에, GraphQL SDL 문법을 별도로 작성해야 하는 부담이 있습니다.
개인적인 평가
제 개인적인 견해로는 Strawberry의 방식이 가장 Pythonic 한것 같습니다. Django처럼 python type과 별도 호환이 필요한것도 아니고, Ariadne처럼 type_defs SDL을 별도로 관리해줄 필요도 없습니다.
문서화 수준과 개발자 경험 (DX)
개발자 경험(DX)은 학습 곡선, 문서의 친절함, 사용 시 장애 요소 등을 포함합니다. 세 라이브러리는 이 부분에서 다음과 같은 장단점을 보입니다.
Graphene
오랜 기간 사용되었지만 공식 문서화가 다소 빈약하고 최신 업데이트를 충분히 반영하지 못한 면이 있습니다. (개인적으로 ASGI의 공식문서를 보는 느낌이 들었을 정도로 재미없는 공식문서입니다.) 특히 Graphene v3로 업그레이드되는 동안 문서와 주변 도구들이 늦게 따라와 혼란이 있었고, 예를 들어 DataLoader 문서가 깨져 한동안 제대로 안내되지 않았다는 지적도 있었습니다.
그럼에도 Graphene은 성숙한 생태계를 갖추고 있어, Stack Overflow 등 Q&A나 블로그 게시물이 풍부한 편입니다. 다만 2020~2021년 경 프로젝트가 잠시 정체되면서 유지보수 부재 논란이 있었고, 실제로 2021년에는 maintainer를 모집하는 공지가 올라오기도 했습니다. 이후 다행히 새로운 기여자들이 참여하여 현재는 릴리스가 이어지고 있지만, 이러한 과거 때문에 미래 지원에 대한 우려가 있는것도 사실입니다.
Strawberry
비교적 신생 프로젝트지만 문서가 잘 정비되어 있고, 예제와 API 레퍼런스가 명확합니다. FastAPI 등 최신 프레임워크 철학과 맞닿아 있어 학습 개념도 쉽게 와닿으며, 공식 문서도 타입 힌트의 활용, Pydantic 통합 등 실용적인 내용을 담고 있습니다. 실제로 Graphene 사용 중 겪었던 서드파티 라이브러리 호환성 문제(예: 구독 프로토콜, 오래된 의존성 등)들이 Strawberry에서는 비교적 원활하게 해결되었고, Async 지원이나 최신 GraphQL 기능(예: 서브스크립션, 데이터로더)도 기본 제공 또는 쉽게 사용할 수 있도록 되어 있습니다.
다만 Strawberry는 아직 버전 1.0 이전(현재 0.x대)이라 API가 완전히 안정된 상태는 아니며 종종 breaking change가 발생할 수 있습니다. 그럼에도 활발한 개발과 빈번한 릴리스로 이슈 해결이 빠르고, Discord 등지에서 활발한 커뮤니티 지원을 받을 수 있습니다.
Ariadne
문서와 예제가 잘 제공되어 있고, 개념이 단순하여 진입 장벽이 높지 않습니다. 공식 사이트의 튜토리얼이나 블로그 글을 통해 SDL 작성부터 ASGI 앱 구동까지 간단한 예제로 쉽게 따라할 수 있습니다. Ariadne의 철학이 "작고 기억하기 쉬운 API"를 지향하여, 실제 사용해보면 필요한 기능만 최소한의 API로 제공해 직관적입니다.
예를 들어 make_executable_schema로 스키마 문자열과 리졸버를 연결하고, GraphQL ASGI 앱으로 서비스하는 흐름이 명쾌합니다:
import os
from ariadne import make_executable_schema
from ariadne.asgi import GraphQL
from mygraphql import type_defs, resolvers
schema = make_executable_schema(type_defs, resolvers)
application = GraphQL(schema)
개발자 경험 측면에서 GraphQL 스키마 설계와 Python 코드를 분리하는 것을 선호하는 경우 Ariadne이 만족도를 줄것으로 보입니다. 반면, 대규모 프로젝트에서 Python 타입 시스템과 연계된 도구(Mypy, Pydantic 등)를 활용한 개발 편의는 Ariadne에서 자동으로 얻기 어렵습니다. 모든 타입 정의를 GraphQL SDL로 수동 관리해야 하므로, 코드 상에서 타입참조 추적이나 에디터 자동완성 같은 부분은 Strawberry보다 부족할 수 있습니다. 요약하면 Ariadne은 심플함이 강점이지만, Python 도구들과의 통합된 DX는 상대적으로 단순한 편입니다.
타입 지원: Python 타입 힌트 및 Pydantic 통합
Python 백엔드 개발자에게 타입 시스템과의 통합은 매우 중요한 요소입니다. 각 라이브러리가 Python의 타입 힌트나 데이터 검증 라이브러리(Pydantic 등)와 어떻게 호환되는지 살펴보겠습니다.
Graphene
등장 시기가 Python 타입 힌트가 도입되던 무렵이라, Graphene 자체는 타입 힌트를 활용한 설계는 아닙니다. 스키마 정의에 별도의 graphene 타입 클래스를 사용하기 때문에, IDE 상에서 Python 타입 체크를 해주진 않습니다. 예를 들어 age = graphene.Int()로 필드를 정의해도 해당 클래스의 age 속성은 단순히 GraphQL 필드이지, Python 정수형이라는 힌트를 갖지 않습니다.
따라서 Graphene은 정적 타입 체크 도구(mypy)와의 연계는 부족합니다. 한편 Graphene은 Django 모델이나 SQLAlchemy 모델과의 통합을 통해 모델 필드로부터 GraphQL 필드를 생성하는 기능을 제공하지만, Pydantic 같은 독립적인 검증 모델과의 공식 통합은 없습니다. Pydantic 모델을 GraphQL 스키마로 이용하려면 수동으로 Graphene 타입을 만들어 매핑해야 합니다.
Strawberry
타입 힌트 우선 디자인을 내세운 라이브러리답게, 모든 GraphQL 타입 정의와 필드에 Python 타입 힌트를 사용합니다. 덕분에 개발자는 자연스러운 Python 데이터클래스를 작성하듯이 GraphQL 타입을 정의할 수 있고, IDE 자동완성이나 mypy 같은 도구의 혜택을 누릴 수 있습니다. 또한 Strawberry는 Pydantic과의 통합을 실험적으로 지원하여, 기존 Pydantic 모델을 재사용해 GraphQL 타입을 만들 수 있습니다. 공식 문서에 따르면 "Strawberry는 Pydantic을 지원하며, Pydantic 모델로부터 Strawberry 타입을 생성해 코드를 두 번 작성할 필요를 없애준다"고 합니다. (하지만 저는 아직 experimental 단계의 기능이어서 실제 회사에서는 사용하지 못했습니다.)
strawberry.experimental.pydantic.type 데코레이터를 활용하여... Pydantic의 필드 정의를 읽어들여 자동으로 해당 GraphQL 타입을 생성합니다. 예를 들어, Pydantic 모델 User(BaseModel)이 있을 때:
@strawberry.experimental.pydantic.type(model=User)
class UserType:
id: strawberry.auto
name: strawberry.auto
이렇게 하면 UserType GraphQL 객체 타입이 Pydantic User의 id, name 필드를 그대로 갖게 됩니다. 이 기능 덕분에 데이터 검증(Pydantic)과 GraphQL 스키마 정의를 한 번에 관리할 수 있으며, 중복 모델 정의를 줄일 수 있습니다.
Ariadne
Ariadne은 GraphQL 스키마를 SDL로 정의하므로 Python의 타입 힌트 시스템과 직접적인 연계는 없습니다. GraphQL 스키마 자체의 타입(예: String, Int, 커스텀 타입 등)을 사용하고, 리졸버 함수의 시그니처에는 자유롭게 Python 타입 힌트를 달 수 있지만 그것이 GraphQL 스키마에 반영되진 않습니다. 따라서 정적 타입 체크나 에디터 지원 측면에서는 Ariadne이 특별한 도움을 주지 않습니다. Pydantic과의 통합도 별도로 제공되지 않습니다.
하지만, 필요하다면 리졸버 구현 내에서 Pydantic 모델을 활용할 수는 있습니다. 예를 들어, 뮤테이션 인자로 받은 딕셔너리를 Pydantic 모델로 파싱하여 검증하거나, 반대로 반환할 객체를 Pydantic 모델로 생성한 뒤 .dict()로 직렬화해 돌려주는 식으로 수작업 통합은 가능합니다. 이것은 순전히 개발자 몫이며, 프레임워크 차원의 지원은 아니죠. 정리하면 Ariadne은 타입 힌트/모델 통합보다는 GraphQL 스키마 자체에 집중한 라이브러리입니다.
주요 웹 프레임워크와의 통합성
GraphQL 라이브러리 선택 시, 사용 중인 웹 프레임워크와 쉽게 통합되는지도 고려해야 합니다. FastAPI, Django 같은 인기 프레임워크와의 통합 현황을 비교해보겠습니다.
FastAPI와 ASGI 프레임워크
FastAPI는 공식 문서에서 Strawberry를 권장할 정도로 Strawberry와의 궁합이 뛰어납니다.
Strawberry는 strawberry.fastapi.GraphQLRouter를 제공하여 FastAPI 애플리케이션에 손쉽게 GraphQL 엔드포인트를 추가할 수 있습니다. app.include_router(GraphQLRouter(schema), prefix="/graphql") 한 줄로 통합이 가능합니다
import strawberry
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
@strawberry.type
class User:
pass
@strawberry.type
class Query:
pass
schema = strawberry.Schema(query=Query)
graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
Graphene의 경우, Starlette(및 FastAPI)에서 GraphQL을 쓰려면 별도의 어댑터가 필요했습니다. 예전에는 Starlette의 GraphQLApp 클래스를 사용했으나 deprecated 되었고, 현재는 타사 라이브러리인 starlette-graphene3를 이용해 FastAPI에 Graphene을 붙일 수 있습니다. 이는 동작은 하지만 공식 지원이 아닙니다.
Ariadne은 ASGI 앱 자체로 동작하므로 FastAPI에 손쉽게 mount할 수 있습니다. app.mount("/graphql", GraphQL(schema)) 형태로 서브 애플리케이션으로 붙이거나, FastAPI 라우터 내부에서 GraphQL(schema).handle_http 등을 직접 endpoint로 사용하는 방식도 가능합니다. 실제로 Starlette, FastAPI, Flask 등과의 통합 예제가 문서에 제공됩니다.
from ariadne import QueryType, make_executable_schema
from ariadne.asgi import GraphQL
from fastapi import FastAPI
type_defs = """
type Query {
hello: String!
}
"""
query = QueryType()
@query.field("hello")
def resolve_hello(*_):
return "Hello world!"
# Create executable schema instance
schema = make_executable_schema(type_defs, query)
# Mount Ariadne GraphQL as sub-application for FastAPI
app = FastAPI()
app.mount("/graphql/", GraphQL(schema, debug=True))
Django
Graphene은 Django 환경에서 가장 오래 사용된 GraphQL 솔루션입니다. graphene-django 패키지를 통해 Django의 ORM 모델을 Graphene 타입으로 쉽게 변환하고, Django view로 GraphQL 엔드포인트(/graphql)를 제공할 수 있습니다. Graphene-Django는 Django의 권한 체계나 필터 셋과 연동하는 등 편의 기능도 많아 성숙한 상태입니다.
Strawberry도 최근 strawberry-graphql-django패키지를 통해 Django 통합을 제공하고 있습니다. Django 모델로부터 Strawberry 타입을 생성하거나, Django의 urlpatterns에 GraphQL view를 추가하는 기능을 갖추고 있지만, 성숙도는 이제 올라오는 단계입니다. Graphene-Django가 수년간 다듬어져 온 것에 비해 Strawberry-Django는 비교적 새롭지만, 활발한 개발이 이루어지고 있rh 점차 안정화되고 있습니다.
Ariadne도 Django 통합을 지원하는 별도 패키지(ariadne_django)가 있어서, GraphQLView.as_view()를 통해 Django의 URL 패턴에 GraphQL 엔드포인트를 등록할 수 있습니다.
Django에서 Ariadne를 사용하면 GraphQL 스키마는 SDL로 정의하고, 각 앱별로 SDL 조각과 resolver 함수를 모듈화하여 구성하는 패턴을 취할 수 있습니다. Django 환경에서는 Graphene과 Ariadne 둘 다 많이 사용되고 있고, Strawberry는 신흥 대안으로 자리잡는 추세입니다.
프로젝트 유지보수 상태 및 커뮤니티 활동
오픈소스 라이브러리의 유지보수 현황과 커뮤니티 규모도 무시할 수 없는 요소입니다. 장기적으로 사용할 기술이라면 업데이트 주기나 이슈 대응 속도, 사용자 풀 등을 봐야 합니다.
Graphene
2015년경부터 개발되어 가장 역사가 오래된 Python GraphQL 라이브러리 중 하나입니다. 스타 수, 다운로드 수 등 인지도나 사용자 기반이 가장 크다고 볼 수 있습니다. 다만 앞서 언급했듯 한때 주요 유지관리자들의 손이 떠나 프로젝트가 정체되었던 시기가 있었습니다.
현재는 여러 기여자의 참여로 다시 활기를 찾았고, 2022년 Graphene 3.x 정식 버전이 나오면서 꾸준한 릴리스가 이뤄지고 있습니다. Graphene-Django나 Graphene-SQLAlchemy 같은 서브 프로젝트들도 커뮤니티 주도로 관리되고 있습니다. 커뮤니티 Q&A는 많지만, 오래된 이슈나 v2 기준의 답변도 많아 정보를 걸러볼 필요는 있습니다.
Strawberry
2019년경 등장하여 빠르게 성장한 프로젝트입니다. 아직 버전 1.0은 아니지만 0.x 버전대에서 거의 매주 단위의 빈번한 업데이트가 진행되고 있습니다. Graphene 핵심 개발자 출신 등이 참여해 만들었기 때문에 Graphene의 단점을 보완하려 노력하고 있으며, 커뮤니티도 Discord, GitHub Discussions 등을 통해 활발합니다.
Ariadne
2018년경부터 시작되어 현재까지 꾸준히 유지보수되고 있습니다. 주로 Django 기반 커머스 플랫폼 Saleor를 만든 Mirumee사가 중심이 되어 개발한 것으로 알려져 있으며, 해당 회사 프로젝트에서 활용하면서 안정성을 높여온 케이스입니다.
현재 버전도 0.x이지만 (최근 2025년 2월에 0.26 버전 릴리스), 이는 Semantic versioning을 엄격히 따르는 것일 뿐 기능은 충분히 안정적입니다. 커뮤니티 규모는 Graphene이나 Strawberry보다 작아 보이지만, GraphQL을 선호하는 Python 개발자들 사이에서는 평판이 좋은 편입니다. Slack/Discord 같은 공식 커뮤니티와 GitHub 이슈를 통해 질문을 해결할 수 있고, GraphQL 표준에 맞춰 돌아가는 만큼 일반 GraphQL 자료들도 참고 가능합니다.
Strawberry를 선택할 만한 이유
위의 비교 요소들을 종합해보면, Strawberry를 선택하는것은 타입힌트를 선호하는 Python 개발자에게는 좋은 선택일 것이며, 특히 FastAPI를 이용중인 팀에게는 가장 나은 대안이 될 것으로 보입니다.
실제로 몇 줄의 코드만으로 GraphQL 라우트를 추가할 수 있었고, FastAPI의 의존성 주입이나 보안 처리도 Strawberry의 컨텍스트 기능과 잘 연계되었습니다.
저는 Strawberry로 GraphQL을 구현할 때 Python 코드와 GraphQL 스키마 사이의 갭이 느껴지지 않았고 자연스러웠습니다. 반면 Graphene은 Django 스타일이라 호불호가 있었고 (우리 팀에는 Django 경험이 적은 인원도 있어 학습이 필요해 보였습니다.), Ariadne은 SDL 작성에 익숙하지 않은 몇몇에게 초기 진입장벽이 존재했습니다.
유지보수와 향후 전망도 선택에 영향을 줄것입니다. 물론 미래일은 알 수 없지만, 최근의 모멘텀만 보자면 Strawberry는 적극적으로 개선되고 있어 새로운 GraphQL 기능이나 버그 수정이 빠른것으로 파악되었스빈다. Graphene은 현재도 사용자가 많지만 만약 메인테이너 이탈이 다시 생긴다면 대응이 느려질 수 있다는 걱정이 있었죠. Ariadne도 안정적이지만 개발 커뮤니티의 규모가 Strawberry만큼 크진 않아 정보 구하기 측면에서는 Strawberry 쪽이 나았습니다.
마지막으로, 기능성 측면도 Strawberry는 부족함이 없었습니다. GraphQL 서브스크립션, 파일 업로드, 권한 제어 등 필요한 기능을 플러그인이나 내장 기능으로 지원했고, Graphene에서 쓰던 방식을 거의 대등하거나 더 편리한 방법으로 대체할 수 있었습니다. 예컨대 Graphene-Django에서 쓰던 JWT 인증 미들웨어를 Strawberry의 dependencies로 손쉽게 재구현하거나, DataLoader를 활용해 N+1 문제를 해결하는 것도 Strawberry가 잘 지원했습니다.
이러한 이유들로, Python을 이용하는 팀이 Strawberry를 GraphQL 개발에 사용하는 것은 좋은 선택이 될 것입니다. 개발 속도 뿐만 아니라 개발자 경험 측면에서도 좋은 선택으로 보입니다.
'탐구 생활 > GraphQL' 카테고리의 다른 글
GraphQL vs REST vs gRPC: 개념과 설계 철학, 성능 특성 비교 (0) | 2025.03.29 |
---|