RESTful

  • URI (고유한 주소) > URL (like 파일위치) : API에서는 URI라고 하는 것이 더 정확하다.
  • URI 설계
    • 컬렉션은 복수를 사용한다.
    • CRUD는 URI에 사용하면 안된다.
      • Create: POST
      • Read: GET
      • Update: PUT (통째로 교체)
      • Destroy: DELETE
      • +) PATCH(Update, 일부분만 교체)

Class-based views

  • 재사용가능한 뷰를 만들기 좋다.
  • 모든 뷰는 View 클래스를 상속받아 사용한다.

Introduction to class-based views

  • 특정 HTTP 메소드 (GET, POST 등)와 관련된 코드의 구성을 조건문 분기 대신 별도의 메소드로 처리
  • 믹스인(다중 상속)과 같은 객체 지향 기술을 사용하여 코드를 재사용 가능
    • Mixin : 기본적으로 사용하는 것에 추가하여 사용한다는 의미
    • 예: class TemplateView(TemplateResponseMixin, ContextMixin, View)
    • 기본적으로 사용되는 View에 기능확장을 위해 두 가지 mixin을 추가
    • 믹스인을 잘 사용하면 자신에게 필요한 CustomView를 만들기 유용

The relationship and history of generic views, class-based views, and class-based generic views

Only view function > Function-based Generic View > Class-based Generic View

  • Generic View : 자주 쓰이는 뷰들을 추상화된 공통적인 패턴으로 정의 (가장 많이 사용)

Using class-based views

클래스 기반 뷰를 사용하면 조건문 분기 코드가 아닌 다른 클래스 인스턴스 메서드를 사용하여 여러 HTTP 요청 메서드에 응답 할 수 있다.

뷰 함수에서 HTTP GET을 처리 할 코드는 다음과 같다.

# view function
from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')

클래스 기반 뷰에서는 다음과 같다.

# class-based view
from django.http import HttpResponse
from django.views import View

class MyView(View):
	# get 요청 처리
    def get(self, request):
        # <view logic>
        return HttpResponse('result')

장고 URL resolver는 request와 (클래스가 아니라) 함수가 올것을 기대한다. 클래스 기반 뷰는 as_view() 메서드를 가지고 있는데, 이 메서드는 URL과 매치되는 패턴이 도착하면 함수를 반환한다. 이 함수는 클래스의 인스턴를 만들고 dispatch() 메서드를 호출한다.

dispatch()는 요청이 GET, POST 등인지 여부를 확인하고 일치하는 메소드가 정의되어있는 경우 해당 요청을 중계하거나 그렇지 않은 경우 HttpResponseNotAllowed를 발생시킨다.

# urls.py
from django.conf.urls import url
from myapp.views import MyView

urlpatterns = [
    url(r'^about/$', MyView.as_view()),
]

Using mixins

믹스인은 여러 상위 클래스의 행위와 속성을 결합 할 수있는 다중 상속의 한 형태이다.

  • 여러 클래스에서 코드를 재사용 할 수있는 훌륭한 방법이다.
  • 하지만, 많은 코드가있는 클래스를 상속하는 경우 어떤 mixins에서 어떤 메소드를 재정의 할 것인지를 아는 것이 어렵다.
  • 주의 : 하나의 generic view에서만 상속 할 수 있다.
    • 예를 들어, 하나의 상위 클래스 View에서 상속 할 수 있으며
    • 나머지는 (있는 경우) 믹스인 이어야한다.

Django REST Framework

Tutorial 1: Serialization

Serializers

querysets 및 모델 인스턴스와 같은 복잡한 데이터를 JSON, XML 또는 (기타 컨텐트 유형으로 쉽게 렌더링 할 수있는) native Python 데이터 유형으로 변환한다.

Serializer

snippet 인스턴스를 json과 같은 표현으로 serializing 및 deserializing해야 한다. serializers를 사용해 쉽게 구현할 수 있다.

from rest_framework import serializers
from snippets.models import Snippet

# 파이썬 객체로 만들고(create), 업데이트(update)하는 클래스
class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    # ...

    def create(self, validated_data):
        # create(**kwargs) : 딕셔너리 형 데이터의 key-value를 자동으로 넣어 처리
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        # ...

        # 객체 인스턴스가 장고 모델과 일치하면 데이터베이스에 저장 가능
        instance.save()
        return instance

ModelSerializers

# ModelSerializer class
class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

    # create() 메서드와 update() 메서드가 이미 구현되어 있다.

Postman 테스트

Postman > POST method Body > Raw > Json 으로 요청

{
	"title": "Test Snippet",
	"code": "class MyUser(AbstractUser):\n\timg_profile = models.ImageField(upload_to='user', blank=True)",
	"linenos": true,
	"language": "python",
	"style": "default"
}

Tutorial 2: Requests and Responses

Adding optional format suffixes to our URLs

Response 객체는 클라이언트가 요청한 형태로 콘텐츠를 렌더링한다. 이 장점을 활용하기 위해, API를 개선한다. 다음과 같은 URI를 사용할 수 있게 된다.

  • http://example.com/api/items/4
  • http://example.com/api/items/4.json
  • http://example.com/api/items/4.xml (XML 제공)

Browsability

web-browsable API를 지원하지만, 실제 production에 사용하면 안된다.

Tutorial 3: Class-based Views

Using mixins

# GenericAPIView 제너릭뷰로 받고,
# GET 요청이면 ListModelMixin으로 실행
# POST 요청이면 CreateModelMixin으로 실행
class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    # 직렬화 함수는 1개만 사용 가능
    serializer_class = SnippetSerializer

    # GET 요청
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    # POST 요청
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

Using generic class-based views

생성/조회/업데이트/삭제는 굉장히 일반적인 일이다. 그래서 REST framework는 mixed-in generic view로 제공한다.

class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

과제

  • API 테스트 코드 작성 (참고)