2. Requests and Responses

hyuckhoon.ko·2023년 9월 28일

1. Requests objects

HttpRequest를 확장한 Request가 사용되는데, request 파싱을 쉽게 도와준다. 핵심은 request.data다.
장고 튜토리얼에서 봤었던 request.POST 보다 request.data를 사용하자.


2. Response objects

DRF에서는 Response 객체를 사용한다.
TemplateResponse의 한 형식으로써 렌더링되지 않은 내용을 가져다가 content negotiaion을 통해 클라이언트에 반환할 올바른 내용 유형을 결정한다.


3. Status codes

DRF는 좀 더 명시적인 상태 코드를 제공한다.
예를 들어,HTTP_400_BAD_REQUEST같이 말이다.
단순히 숫자 정보만 담긴 상태코드를 리턴하는 것보다 더 좋은 방법이다.


4. Wrapping API views

DRF는 2개의 wrapper를 제공한다.

1) @api_view 데코레이터

FBV(Funtion Based View)에 사용된다.

2) APIView 클래스

CBV(Class Based View)

이러한 wrapper가 제공하는 기능은 무엇이 있을까?

  • API가 Request 인스턴스들을 입력을 받는다는 것을 명시적으로 확인
  • Response에 context를 추가할 수 있게 되어 content
  • 허용되지 않는 메서드의 요청등에 대한 응답이 가능(405 Method Not Allowed)
  • 잘못된 형식의 입력에 대해 request.data 수준에서 파싱 에러를 일으킬 수 있음

5. 적용해보기

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@api_view(["GET", "POST"])
def snippet_list(request):
    """
    - List all code snippets
    - Create a new snippet"""

    if request.method == "GET":
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == "POST":
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(["GET", "PUT", "DELETE"])
def snippet_detail(request, pk):
    """
    - Retrieve
    - Update
    - Delete
    """

    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == "GET":
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == "PUT":
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == "DELETE":
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

많은 변화가 있다.

  • request.data를 통한 request 데이터 값 접근
    request.data는 request의 json 요청들을 처리할 수도 있지만, 다른 형식의 요청들도 처리할 수 있다.
    이전 챕터에서는 명시적으로 아래와 같이 파싱했어야 했다.
    data = JSONParser().parse(request)
  • status.HTTP_204_NO_CONTENT 같은 명시적인 HTTP 상태코드

6. json이 아닌 다른 형식은 어떻게 처리할까?


### views.py
def snippet_list(request, format=None):

def snippet_detail(request, pk, format=None):


### urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views


urlpatterns = [
    path("snippets/", views.snippet_list),
    path("snippets/<int:pk>/", views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

Accept 헤더를 사용하여 다른 형식의 데이터를 받아보자.

pip install httpie

Request JSON

>>> http http://127.0.0.1:8000/snippets.json


HTTP/1.1 200 OK
Allow: GET, OPTIONS, POST
Content-Length: 319
Content-Type: application/json
Cross-Origin-Opener-Policy: same-origin
Date: Thu, 28 Sep 2023 07:13:28 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.10.10
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "code": "foo = \"bar\"\n",
        "id": 1,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print(\"hello, world\")\n",
        "id": 2,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print(\"hello, world\")",
        "id": 3,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    }
]

Request HTML

http http://127.0.0.1:8000/snippets/ Accept:text/html   

Browsability

이를 통해 DRF는 클라이언트가 요청한 content type에 기반한 응답을 제공해 준다. DRF를 사용해보면 알 수 있듯이, 클라이언트가 웹 브라우저에서 DRF를 사용할 때 HTML 형식의 representation으로 리턴한다.

web-browsable API는 이점이 많다.
개발을 할 때 API를 디버깅하고 사용하기에도 편하다.

0개의 댓글