기존 블로그의 글을 옮겨온 글임 From. 2019.10.15
제작중인 서비스형 블로그의 발전을 위해서 RESTful
과 프론트엔드 프레임워크의 도입을 시도하고자 하였다. RESTful API
의 개념은 어느정도 알고 있었지만 이를 어떻게 장고에서 구현하여 활용하는지가 핵심적인 궁금증이다.
REST API란?
REST는 Representational State Transfer의 약어로서 웹의 장점과 HTTP의 우수성을 제대로 활용할 수 있는 아키텍처이다. HTTP URI를 통해서 자원을 명시하고 HTTP Method(POST, GET, PUT, DELETE)를 통해서 명시된 자원의 CURD 연산을 적용하는 것을 의미한다.
따라서 REST는 자원(Resource), 행위(Verb), 표현(Representations)으로 구성된 아키텍처라 볼 수 있으며 미디움의 어떤 글을 보고 필요성에 대해서 느낄 수 있었다. 해당 글을 정리하자면 코드의 재사용성을 높일 수 있으며 프론트엔드와 백엔드의 완전한 분업이 가능하다고 말한다.
REST API의 특징
REST 아키텍처는 다음과 같은 특징을 가지고 있다.
Uniform Interface
URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일이다. HTTP 표준 프로토콜을 따르는 모든 플랫폼에서 사용이 가능하다.
Stateless
작업을 위한 상태 정보(쿠키, 세션)를 보관하거나 관리하지 않고 요청만 처리하면 되므로 구현이 단순해진다.
Cacheable
웹 표준 프로토콜을 그대로 사용하므로 기존의 인프라를 활용할 수 있으므로 캐싱 기능을 사용할 수 있다.
Self-descriptiveness
REST API 메시지만 보고도 쉽게 이해할 수 있는 자체 표현 구조로 되어 있다.
Client-Server
자원을 가진 쪽이 Server, 자원을 요청하는 쪽이 Client 각각의 역할이 확실히 구분되기 때문에 서로간 의존성이 줄어들게 됨
- Server : API를 제공하고 비즈니스 로직 처리 및 저장을 책임
- Client : 사용자 인증이나 상태정보를 직접 관리하고 책임
Layered System
REST 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수 있게 한다.
디자인 가이드
URI는 정보의 자원을 표현해야 한다.
블로그 서비스라는 가정하에 아래와 같이 URI를 표현할 수 있다.
/posts/N (포스트)
/members/N (멤버)
주의사항은 다음과 같다.
- 슬래시는 계층 관계를 나타낼 때 사용
- 마지막 문자로 슬래시를 포함하지 않음
- 하이픈은 가독성 높이는데 사용
- 언더바는 사용하지 않음
- 소문자가 적합함
- 파일 확장자는 포함하지 않음
계층 관계는 어떻게 표현할까?
/members
/members/N
/members/N/likes
자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.
잘못된 예
POST /members/create (회원 정보 추가함)
GET /members/N/get (회원 정보 가져옴)
POST /members/N/update (회원 정보 수정함)
POST /members/N/delete (회원 정보 삭제함)
올바른 예
GET /members/N (회원 정보 가져옴)
POST /members/N (회원 정보 추가함)
PUT /members/N (회원 정보 수정함)
DELETE /members/N (회원 정보 삭제함)
HTTP 응답코드
코드 | 내용 |
---|---|
200 | 클라이언트의 요청을 정상적으로 수행함 |
201 | 클라이언트가 어떠한 리소스 생성을 요청 이후 성공적으로 생성됨 |
400 | 클라이언트의 요청이 부적절함 |
401 | 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드(로그인 하지 않은 유저가 로그인 했을 때, 요청 가능한 리소스를 요청했을 때) |
403 | 유저 인증과 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때(400, 404를 사용하는 것을 추천) |
405 | 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드 |
301 | 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을 때 사용 |
500 | 서버에 문제가 있을 경우 사용하는 응답 코드 |
장고 REST API 구현
이것을 서비스에 적용하려면 어떻게 구현해야 할까? 직접 HTTP Method
와 Content-type
을 알아내고 적절한 응답을 해야할까 고민했으나 곧이어 DjangoRESTframework
가 있다는 것을 알게 되었다. 튜토리얼을 보고 따라했는데 의외로 정말 간단한 것에 대하여 놀랐으나 실제로 서비스에 적용하려면 응용을 더 해봐야 할 듯 하다.
장고를 이용하여 일반적인 웹 서버를 개발할 때와 REST Framework를 활용했을 때 느껴진 차이점은 아래와 같았다.
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'groups']
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ['url', 'name']
그간 한번도 다뤄보지 않았던 Serializer
라는 것을 구현한다. Form
과 비슷한 구조로 구현하는 듯 보였다.
from tutorial.quickstart.serializers import UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
또한 urls.py
에서 view.py
함수를 연결하여 구현하는 것이 일반적이라 생각했지만 REST
에서는 위와 같이 view
를 구현하고
from rest_framework import routers
from tutorial.quickstart import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
views.py
에서 구현된 클래스들은 urls.py
에서 router
라는 객체가 연결해준다. 이는 rest_framework
의 내부 동작이므로 자세한 내용은 문서를 읽어야 파악이 가능할 듯 보인다. 또한 디자인 가이드 몇몇이 지켜지지 않는 것 같아 보였는데, 이도 세부설정이 가능한지 살펴봐야 할 것 같다.
느낀점
구현이 간단해지는 프레임워크의 도입은 환영이라 생각한다. 튜토리얼만 진행한 RESTful API는 그러한 느낌이었다. 다만 REST API가 정말 쉬운 아키택쳐 인지는 잘 모르겠다. HTTP와 REST에 대한 명확한 이해가 필요해 보인다.
위 영상을 최근에야 제대로 보았는데 웹과 REST
에 대해서 전체적인(왜? 어떻게? 만들었는지 등) 설명을 해주셔서 굉장히 좋았다. 또한 필자는 항상 궁금증을 가지고 있었다. 정말 내 프로젝트에 이 REST API를 도입하는게 맞는가에 대해서. 그 고민을 이 영상이 해결해 주었다. 적용하지 않을 것 같다. (현재는 부분부분 도입중) 공부는 하겠지만...
Ghost