DRF3 튜토리얼 5 - 관계 & 하이퍼링크 API
원문 - Relationships and Hyperlinked APIs
번역을 허락해 준 Tom Christie에게 고마움을 전합니다.
튜토리얼 5: 관계 & 하이퍼링크 API
지금까지 우리가 만든 API에서 '관계'는 주 키(primary key)로 나타나고 있었습니다. 이번 튜토리얼에서는 API의 발견성(discoverability)과 응집력(cohesion)을 향상시키고자 관계를 하이퍼링크로 나타내 보겠습니다.
API의 최상단에 대한 엔드 포인트 만들기
지금까지 '코드 조각'과 '사용자'에 대한 엔드 포인트를 만들었지만, 아직까지 이렇다 할 API의 시작점은 없었습니다. 이를 만들기 위해 평범한 함수 기반 뷰와 @api_view
데코레이터(2부 참고)를 사용해 보겠습니다. snippets/views.py
파일을 여세요.
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
@api_view(('GET',))
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'snippets': reverse('snippet-list', request=request, format=format)
})
여기서 URL을 만드는 데 reverse
함수를 사용한 점을 주목하세요.
코드 조각의 하이라이트 버전에 대한 엔드 포인트 만들기
우리 API에서 아직까지 만들지 않은 부분은 바로, 코드 조각의 하이라이트 버전을 볼 수 있는 방법입니다.
API의 다른 부분과는 달리 이번에는 JSON 대신 HTML 형태로 나타내겠습니다. REST 프레임워크에서 HTML로 렌더링하는 방식은 두 가지 정도가 있는데, 하나는 템플릿을 사용하는 것이고, 다른 하나는 미리 렌더링된 HTML을 사용하는 것입니다. 이번에는 후자가 더 어울려 보입니다.
하이라이트된 코드 조각을 보여주려고 할 때 주의해야 할 점 하나는, 우리가 사용할 만한 제네릭 뷰가 없다는 것입니다. 오브젝트 자체가 아니라, 오브젝트의 속성 하나를 반환할 것이기 때문입니다.
제네릭 뷰 대신 평범한 클래스를 사용하고, .get()
메서드를 구현하겠습니다. snippets/views.py
파일에 다음 내용을 추가하세요.
from rest_framework import renderers
from rest_framework.response import Response
class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all()
renderer_classes = (renderers.StaticHTMLRenderer,)
def get(self, request, *args, **kwargs):
snippet = self.get_object()
return Response(snippet.highlighted)
지금까지 그래왔듯이, 새 뷰는 URL 설정에서도 연결해야 합니다.
snippets/urls.py
파일에서 최상단 url을 방금 만든 뷰로 연결합시다.
url(r'^$', views.api_root),
하이라이트된 코드 조각을 볼 수 있는 url에 대한 패턴도 추가합니다.
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
하이퍼링크로 API 연결하기
요소들 사이의 관계를 다루는 일은 웹 API 설계에서 또 하나의 도전 과제입니다. 관계를 표현하는 방법은 꽤 다양합니다.
- 주 키(primary key)
- 하이퍼링크
- 관계 요소의 식별 가능한 슬러그(slug) 필드
- 관계 요소의 기본 문자열 표현
- 포함된 관계 요소에 대한 표현
- 이 외에도 사용자화된 표현
REST 프레임워크에서는 모든 방법을 지원합니다. 관계 혹은 역관계에 적용하거나, 제네릭 외부 키(foreign key)처럼 사용자화된 manager에 적용할 수도 있습니다.
여기서는 하이퍼링크 방식을 채택하겠습니다. 이러게 하려면 기존에 사용했던 ModelSerializer
를 HyperlinkedModelSerializer
로 변경해야 합니다.
HyperlinkedModelSerializer
는 다음과 같은 점들이 다릅니다.
pk
필드는 기본 요소가 아닙니다.HyperlinkedIdentityField
를 사용하는url
필드가 포함되어 있습니다.- 관계는
PrimaryKeyRelatedField
대신HyperlinkedRelatedField
를 사용하여 나타냅니다.
기존 시리얼라이저에 하이퍼링크를 추가하기는 쉽습니다. snippets/serializers.py
파일에 다음 내용을 추가합시다.
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ('url', 'highlight', 'owner',
'title', 'code', 'linenos', 'language', 'style')
class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
class Meta:
model = User
fields = ('url', 'username', 'snippets')
이 코드에서는 새롭게 'highlight'
필드가 추가되었습니다. 이 필드는 url
필드와 같은 타입이며, 'snippet-detail'
url 패턴 대신 'snippet-highlight'
url 패턴을 가리킵니다.
앞에서 URL의 format 접미어로 '.json'
을 붙였듯이, highlight
필드에는 format 접미어로 '.html'
을 붙였습니다.
URL 패턴에 이름 붙이기
하이퍼링크 API를 만들고 싶다면, URL 패턴에 이름을 붙여야 합니다. 어떤 패턴들인지 살펴봅시다.
- API의 최상단은
'user-list'
와'snippet-list'
를 가리킵니다. - 코드 조각 시리얼라이저에는
'snippet-highlight'
를 가리키는 필드가 존재합니다. - 사용자 시리얼라이저에는
'snippet-detail'
을 가리키는 필드가 존재합니다. - 코드 조각 시리얼라이저와 사용자 시리얼라이저에는
'url'
필드가 존재합니다. 이 필드는 기본적으로'{모델_이름}-detail'
을 가리키며 따라서'snippet-detail'
과'user-detail'
을 가리킵니다.
이 이름들을 URL 설정에 넣었다면 snippets/urls.py
파일은 다음과 같을 겁니다.
from django.conf.urls import url, include
# API endpoints
urlpatterns = format_suffix_patterns([
url(r'^$', views.api_root),
url(r'^snippets/$',
views.SnippetList.as_view(),
name='snippet-list'),
url(r'^snippets/(?P<pk>[0-9]+)/$',
views.SnippetDetail.as_view(),
name='snippet-detail'),
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$',
views.SnippetHighlight.as_view(),
name='snippet-highlight'),
url(r'^users/$',
views.UserList.as_view(),
name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$',
views.UserDetail.as_view(),
name='user-detail')
])
# 탐색 가능한 API를 위한 로그인/로그아웃 뷰
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
페이징 기능 추가하기
사용자나 코드 조각의 목록이 꽤 긴 경우가 있을 겁니다. 따라서 결과물을 여러 페이지로 나누어, API 클라이언트 측에서 각 페이지를 하나씩 차례대로 읽어가도록 만들면 좋겠습니다.
tutorial/settings.py
파일을 열어 페이징 설정의 기본 값을 바꿔 봅시다. 다음을 추가합니다.
REST_FRAMEWORK = {
'PAGE_SIZE': 10
}
REST 프레임워크의 모든 설정은 'REST_FRAMEWORK'라는 딕셔너리에 넣어야 합니다. 이렇게 해야 프로젝트의 다른 설정들과 분리할 수 있습니다.
필요에 따라 페이징 스타일을 바꿀 수도 있지만 여기서는 기본 스타일을 따르겠습니다.
탐색 가능한 API
탐색 가능한 API를 브라우저에서 열어서 링크들을 이리 저리 눌러보면, API의 구석구석을 둘러볼 수 있을 겁니다.
또한 코드 조각 인스턴스의 '하이라이트 버전'을 살펴볼 수도 있겠습니다. (HTML 형태입니다.)
튜토리얼 6부에서는 뷰셋과 라우터를 통해 코드 양을 줄이는 방법을 배우겠습니다.
번역에 도움을 주신 파이님께 감사합니다.
COMMENTS