Request and response of DRF Wizard

Keywords: JSON curl REST Python

src

From this section we begin to really touch on the core of rest framework. First, let's learn some necessary knowledge.


1. Request Object -- Request object

The rest framework introduces a Request object inherited from HttpRequest, which provides more flexible parsing of requests. The core part of the request object is the request.DATA attribute, similar to request.POST, but request.DATA is more effective when using WEB API.

request.POST # Only handles form data. Only works for 'POST' method.
request.DATA # Handles arbitrary data. Works any HTTP request with content.



2. Response Object - Response object

The rest framework introduces a Response object, which inherits from the TemplateResponse object. It gets the unrendered content and determines the correct content type to return to the client by negotiating the content.

return Response(data)  # Renders to content type as requested by the client.

3. Status Codes

Using digitized HTTP status codes in views will make your code unreadable and difficult to detect errors in the code. rest framework provides a clearer identification for each status code. For example, HTTP_400_BAD_REQUEST is in the status module. It would be better to use such identifiers throughout views than to use numbers.



4. Encapsulating API views

When writing API views, the REST Framework provides two wrappers:

  1. @api_viwedecorator for working with function based views.
  2. APIView class for working with class based views.

These two wrappers provide many functions, such as ensuring that the Request instance is received in the view and adding content to the Response so that the content negotiation mechanism can be implemented.

The wrapper also provides some behavior, such as returning 405 Methord Not Allowed response when appropriate, and handling any ParseError exception when accessing multiple types of input request.DATA.



5. summary

We started writing some views with these new components.

We no longer need the JESONResponse class (created in the previous article) to delete it. After deletion, we began to refactor our view slightly.

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 snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets)
        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)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


The above code is an improvement on our previous code. It looks more concise and similar to django's forms api form. We also use state codes to make the return value more explicit.



The following is a view update for a single snippet operation:

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a snippet instance.
    """              
    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(snippet, data=request.DATA)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

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

Note that we do not explicitly require requests or responses to give content types. request.DATA can handle incoming json requests, as well as yaml and other formats. Similarly, when response returns data, the REST Framework returns the correct content type to the client.



6. Adding optional format suffixes to URLs

Taking advantage of the fact that there is no need to specify content type in response, we add format suffixes on the API side. Using format suffixes, it is clear that using a format means that our API can handle URL s like http://example.com/api/items/4.json.

Add the format parameter to views, such as:

def snippet_list(request, format=None):

and

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

Now change the urls.py file slightly and add a format suffix pattterns (format_suffix_patterns) to the existing URLs:

from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns

urlpatterns = patterns('snippets.views',
    url(r'^snippets/$', 'snippet_list'),
    url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'),
)

urlpatterns = format_suffix_patterns(urlpatterns)
These additional url patterns are not required.



7. How's it looking?

Continue testing the api from the command line, as we did in Part 1 of the tutorial. All work is very similar, although we have better error handling when sending invalid requests.
We can get a list of all the fragments as before.

curl http://127.0.0.1:8000/snippets/
[{"id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly"}, {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}]

We can control the format of the returned response by using the accept header:

curl http://127.0.0.1:8000/snippets/ -H 'Accept: application/json'  # Request JSON
curl http://127.0.0.1:8000/snippets/ -H 'Accept: text/html'         # Request HTML

Or additional format suffixes:

curl http://127.0.0.1:8000/snippets/.json  # JSON suffix
curl http://127.0.0.1:8000/snippets/.api   # Browsable API suffix

Similarly, we can use content type headers to control the format of requests sent

# POST using form data
curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
{"id": 3, "title": "", "code": "123", "linenos": false, "language": "python", "style": "friendly"}

# POST using JSON
curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
{"id": 4, "title": "", "code": "print 456", "linenos": true, "language": "python", "style": "friendly"}

Now go and open the API in a web browser, by visiting http://127.0.0.1:8000/snippets/.



8. Browsability

Because the api chooses the content type of the response based on the client request, it will return the html format representation of the resource by default when the web browser requests the resource. This allows the api to return a fully Web-browsable html representation.
Having a web browsable API is a huge usability victory, making it easier to develop and use apis. It also greatly reduces barriers for other developers who want to check and use your api.
For more information about browsable API functionality and how to customize it, see the topic "Browsable API] [Browsable API].

Posted by sneamia on Wed, 25 Sep 2019 21:16:17 -0700