Django REST Framework 심층 분석: 견고한 API 구축
Lukas Schneider
DevOps Engineer · Leapcell

소개
오늘날 상호 연결된 디지털 환경에서 API(애플리케이션 프로그래밍 인터페이스)는 현대 애플리케이션을 구축하는 기초 블록입니다. 모바일 앱이 데이터를 가져오든, 단일 페이지 애플리케이션(SPA)이 백엔드와 상호 작용하든, 또는 서비스 간에 통신하든, 견고하고 효율적인 API는 매우 중요합니다. Django 프레임워크를 활용하는 Python 개발자에게 이러한 API 구축은 종종 Django REST Framework(DRF)로 이어집니다. DRF는 RESTful API 생성 프로세스를 크게 간소화하는 강력하고 유연한 도구 상자를 제공합니다. 이 글에서는 DRF의 핵심 구성 요소인 직렬 변환기, 뷰셋, 인증을 심층적으로 분석하여 이러한 구성 요소가 어떻게 함께 작동하여 고품질 웹 서비스를 신속하게 개발할 수 있는지 보여줄 것입니다. 명확한 코드 예제를 통해 원칙, 구현 세부 정보 및 실제 애플리케이션을 탐색하겠습니다.
Django REST Framework의 핵심 구성 요소 이해
구체적인 내용을 자세히 알아보기 전에 DRF에 중요한 핵심 용어와 개념에 대한 기본적인 이해를 확립해 봅시다.
- REST (Representational State Transfer): 네트워킹 애플리케이션을 위한 아키텍처 스타일입니다. 간단하고 확장 가능하며 상태가 없는 시스템을 결과로 만드는 제약 조건 집합을 정의합니다. 주요 원칙에는 리소스, 리소스 식별(URI), 표현을 통한 리소스 조작, 상태가 없는 상호 작용이 포함됩니다.
- API (Application Programming Interface): 다른 애플리케이션이 서로 통신할 수 있도록 하는 정의된 규칙 집합입니다. 소프트웨어 구성 요소가 상호 작용하는 방법을 지정합니다.
- Serializer (직렬 변환기): DRF에서 직렬 변환기는 Django 모델 인스턴스 또는 쿼리셋과 같은 복잡한 데이터 유형을 JSON, XML 또는 기타 콘텐츠 유형으로 쉽게 렌더링할 수 있는 네이티브 Python 데이터 유형으로 변환할 수 있도록 하는 클래스입니다. 반대로 직렬 변환기는 역직렬화, 들어오는 데이터를 구문 분석하고 저장하거나 모델 인스턴스를 업데이트하기 전에 사전 정의된 스키마와 대조하여 유효성을 검사하는 기능도 제공합니다. 본질적으로 Python 객체와 API 데이터 표현 간의 격차를 해소합니다.
- Viewset (뷰셋): 뷰셋은 리소스에 대한 표준 작업(예:
list
,retrieve
,create
,update
,partial_update
,destroy
)에 대한 구현을 제공하는 클래스 기반 뷰의 한 유형입니다. 뷰셋을 사용하면 관련 뷰 집합을 단일 클래스로 결합하여 URL과 논리를 더 간결하고 유지 관리하기 쉽게 만들 수 있습니다. 뷰셋은 라우터와 함께 작동하여 URL 패턴을 자동으로 생성합니다. - Authentication (인증): 사용자 또는 클라이언트의 신원을 확인하는 프로세스입니다. DRF에서 인증 스키마는 누가 요청을 하고 있는지 결정합니다. DRF는 API 엔드포인트를 보호하기 위해 뷰 또는 뷰셋에 쉽게 연결할 수 있는 다양한 인증 클래스(예: 토큰, 세션, 기본)를 제공합니다.
- Permissions (권한): 인증된 사용자 또는 클라이언트가 무엇을 할 수 있는지 결정하는 프로세스입니다. 사용자가 인증되면 DRF의 권한 클래스는 해당 사용자가 특정 리소스에 대해 특정 작업을 수행할 수 있는 동의를 얻었는지 결정합니다.
Serializers (직렬 변환기): 데이터 변환 계층
직렬 변환기는 DRF에서 가장 기본적인 구성 요소이며, Python 객체/데이터베이스 모델과 API 클라이언트가 사용하는 데이터 형식 간의 번역기 역할을 합니다.
원칙 및 구현
직렬 변환기는 두 가지 주요 작업을 수행하도록 설계되었습니다.
- 직렬화: API 응답을 위해 Python 객체(예: Django 모델 인스턴스)를 JSON 또는 XML과 같은 형식으로 변환합니다.
- 역직렬화: API 요청에서 들어오는 데이터를 유효성을 검사하고 데이터베이스 상호 작용을 위해 Python 객체로 변환합니다.
DRF는 여러 유형의 직렬 변환기를 제공하며, ModelSerializer
는 Django 모델에 직접 매핑하는 데 가장 일반적입니다.
간단한 블로그 게시물 API 예시 시나리오
Django 애플리케이션에 Post
모델이 있다고 상상해 봅시다.
# blog/models.py from django.db import models from django.contrib.auth.models import User class Post(models.Model): title = models.CharField(max_length=200) content = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.title
이제 이 Post
모델에 대한 직렬 변환기를 만들어 봅시다.
# blog/serializers.py from rest_framework import serializers from .models import Post class PostSerializer(serializers.ModelSerializer): author = serializers.ReadOnlyField(source='author.username') # ID 대신 사용자 이름을 표시 class Meta: model = Post fields = ['id', 'title', 'content', 'author', 'created_at', 'updated_at'] read_only_fields = ['created_at', 'updated_at'] # 이러한 필드는 서버에서 설정됩니다.
이 PostSerializer
에서:
serializers.ModelSerializer
는Post
모델에서 필드를 자동으로 추론합니다.author = serializers.ReadOnlyField(source='author.username')
는author
필드를 기본 키 대신 작성자의 사용자 이름을 표시하도록 사용자 정의하고 읽기 전용으로 만듭니다.fields
는 포함할 필드를 명시적으로 나열합니다.read_only_fields
는 특정 필드를 읽기 전용으로 표시하여 클라이언트가 직접 수정하지 못하도록 합니다.
애플리케이션
Post
객체를 클라이언트로 보내야 할 때 PostSerializer
는 이를 딕셔너리로 변환하여 JSON으로 렌더링할 수 있습니다. 클라이언트가 JSON 데이터를 보내 게시물을 만들거나 업데이트할 때, 직렬 변환기는 데이터베이스에 저장할 수 있기 전에 정의된 필드와 데이터 유형에 대해 이 데이터를 유효성 검사합니다.
Viewsets (뷰셋): API 엔드포인트 조정
뷰셋은 표준 Django 뷰에 대한 상위 수준의 추상화를 제공하여 단일 클래스에서 리소스에 대한 API 동작을 정의할 수 있도록 합니다.
원칙 및 구현
별도의 list
, create
, retrieve
, update
, destroy
뷰를 작성하는 대신 뷰셋은 이러한 작업을 결합합니다. 이 접근 방식은 특히 DRF의 라우터와 결합될 때 상용구 코드를 크게 줄여줍니다.
예시: 직렬 변환기와 뷰셋 통합
# blog/views.py from rest_framework import viewsets from rest_framework import permissions # 권한 가져오기 from .models import Post from .serializers import PostSerializer class PostViewSet(viewsets.ModelViewSet): queryset = Post.objects.all().order_by('-created_at') serializer_class = PostSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] # 기본 권한 def perform_create(self, serializer): serializer.save(author=self.request.user) # 로그인한 사용자를 작성자로 할당
그런 다음 urls.py
에서 연결합니다.
# drf_project/urls.py (기본 프로젝트 urls.py) from django.contrib import admin from django.urls import path, include from rest_framework.routers import DefaultRouter from blog.views import PostViewSet router = DefaultRouter() router.register(r'posts', PostViewSet) urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(router.urls)), ]
PostViewSet
에서:
queryset
은 객체를 검색하기 위한 기본 쿼리셋을 정의합니다.serializer_class
는PostViewSet
을PostSerializer
에 연결합니다.permission_classes
는 이러한 리소스에 누가 액세스하고 수정할 수 있는지 정의합니다(다음 섹션에서 자세히 설명).perform_create(self, serializer)
는 객체 생성 중에 사용자 정의 논리를 삽입할 수 있도록 하는 재정의된 메서드이며, 이 경우 새 게시물의author
를 현재 로그인한 사용자로 자동 설정합니다.
routers.DefaultRouter
를 사용하면 DRF는 posts
엔드포인트(예: 목록/생성용 /api/posts/
, 검색/업데이트/삭제용 /api/posts/<id>/
)에 대한 모든 표준 CRUD 작업에 대한 URL을 자동으로 생성합니다.
애플리케이션
이 설정은 개발자가 최소한의 코드로 모델에 대한 전체 CRUD 기능을 신속하게 노출할 수 있도록 합니다. DRY(Don't Repeat Yourself) 원칙을 준수하고 특히 많은 리소스가 있는 애플리케이션에서 API 엔드포인트 관리를 단순화합니다.
Authentication (인증): API 보안
인증은 API를 보호하는 첫 번째 방어선으로, 리소스에 액세스하려고 시도하는 클라이언트의 신원을 확인합니다.
원칙 및 구현
DRF의 인증 시스템은 플러그형으로, 다른 인증 스키마 간에 쉽게 전환하거나 결합할 수 있습니다. 요청이 들어오면 DRF는 하나의 인증이 요청을 성공적으로 인증할 때까지 정의된 인증 클래스를 반복합니다.
일반적인 DRF 인증 스키마는 다음과 같습니다.
- SessionAuthentication: Django의 세션 시스템을 사용하는 브라우저 기반 클라이언트에게 이상적입니다.
- TokenAuthentication: 각 요청에 고유 토큰이 전송되는 모바일 및 SPA 클라이언트를 위한 인기 있는 선택입니다.
- BasicAuthentication: 각 요청에 사용자 이름/비밀번호 자격 증명을 보내며, 일반적으로 HTTPS를 통해 전송됩니다.
토큰 기반 인증을 통합해 봅시다.
1. rest_framework.authtoken
을 INSTALLED_APPS
에 추가:
# drf_project/settings.py INSTALLED_APPS = [ # ... 'rest_framework', 'rest_framework.authtoken', # TokenAuthentication용 # ... ]
2. DRF의 인증 구성:
# drf_project/settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.SessionAuthentication', # 브라우저 API 액세스용(선택 사항) ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', # 기본적으로 인증 필요 ] }
3. 사용자에게 토큰 생성(예: 사용자 생성 또는 로그인 시):
# 토큰 생성 엔드포인트를 추가할 수 있습니다. # blog/views.py (또는 전용 인증 앱) from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.authtoken.models import Token from rest_framework.response import Response class CustomAuthToken(ObtainAuthToken): """ 인증 토큰을 얻기 위한 사용자 정의 뷰. 성공적인 로그인 시 사용자 ID와 토큰을 반환합니다. """ def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) return Response({ 'token': token.key, 'user_id': user.pk, 'email': user.email }) # drf_project/urls.py # ... from blog.views import CustomAuthToken # ... urlpatterns = [ # ... path('api/token-auth/', CustomAuthToken.as_view()), ]
이제 클라이언트는 사용자 이름과 비밀번호가 포함된 POST 요청을 /api/token-auth/
로 보내 토큰을 얻을 수 있습니다. 이후 요청은 Authorization: Token <your_token_key>
헤더를 포함해야 합니다.
애플리케이션
인증은 민감한 데이터를 보호하고 API 기능에 대한 액세스를 제어하는 데 중요합니다. 속도 제한 기능이 있는 공개 API를 구축하든 전용 내부 서비스를 구축하든 강력한 인증은 승인된 사용자만 시스템과 상호 작용하도록 보장합니다.
Permissions (권한): 세분화된 액세스 제어
사용자가 인증된 후 권한 클래스는 리소스에 액세스할 수 있는 리소스와 수행할 수 있는 작업을 결정합니다.
원칙 및 구현
DRF의 권한 시스템은 세밀한 제어를 허용합니다. 권한 클래스는 인증 후 적용되며 각 들어오는 요청에 대해 평가됩니다.
예시: 사용자 정의 권한
PostViewSet
에서 permissions.IsAuthenticatedOrReadOnly
를 사용했습니다. 즉, 인증된 사용자는 모든 작업을 수행할 수 있고, 인증되지 않은 사용자는 읽기(GET, HEAD, OPTIONS)만 수행할 수 있습니다.
게시물의 작성자만 게시물을 편집/삭제할 수 있도록 하는 사용자 정의 권한을 만들어 봅시다.
# blog/permissions.py from rest_framework import permissions class IsAuthorOrReadOnly(permissions.BasePermission): """ 객체의 작성자만 편집할 수 있도록 하는 사용자 정의 권한입니다. """ def has_object_permission(self, request, view, obj): # 읽기 권한은 모든 요청에 허용되므로 항상 GET, HEAD 또는 OPTIONS 요청을 허용합니다. if request.method in permissions.SAFE_METHODS: return True # 쓰기 권한은 게시물의 작성자에게만 허용됩니다. return obj.author == request.user
이제 PostViewSet
을 이 사용자 정의 권한을 사용하도록 업데이트합니다.
# blog/views.py # ... from .permissions import IsAuthorOrReadOnly # 사용자 정의 권한 가져오기 class PostViewSet(viewsets.ModelViewSet): queryset = Post.objects.all().order_by('-created_at') serializer_class = PostSerializer permission_classes = [IsAuthorOrReadOnly] # 사용자 정의 권한 사용 # ... (perform_create 메서드는 동일하게 유지)
애플리케이션
사용자 정의 권한은 액세스 제어와 관련된 복잡한 비즈니스 로직을 구현하는 데 매우 유용합니다. 사용자는 권한이 있는 데이터와 기능만 상호 작용하도록 보장하여 API의 보안과 무결성을 향상시킵니다.
결론
Django REST Framework는 개발자가 놀라운 효율성으로 강력하고 확장 가능하며 안전한 웹 API를 구축할 수 있도록 지원합니다. 데이터 변환을 위한 직렬 변환기, 간소화된 API 엔드포인트 생성을 위한 뷰셋, 인증 및 권한을 위한 강력한 시스템이라는 핵심 구성 요소를 이해하고 효과적으로 활용함으로써 기능적이고 유지 관리하기 쉬운 API를 만들 수 있습니다. DRF는 데이터 모델을 동적 API 리소스, 다양한 클라이언트 애플리케이션에 서비스를 제공할 준비로 전환하는 데 필요한 필수 도구를 제공합니다.