2 - Requests and Responses - Django REST Framework
2 - Requests and Responses - Django REST Framework
2 - Requests and Responses - Django REST Framework
Request objects
REST framework introduces a Request object that extends the regular HttpRequest , and provides more
flexible request parsing. The core functionality of the Request object is the request.data attribute, which is
similar to request.POST , but more useful for working with Web APIs.
request.POST # Only handles form data. Only works for 'POST' method.
request.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.
Response objects
REST framework also introduces a Response object, which is a type of TemplateResponse that takes
unrendered content and uses content negotiation to determine the correct content type to return to the client.
Status codes
Using numeric HTTP status codes in your views doesn't always make for obvious reading, and it's easy to
not notice if you get an error code wrong. REST framework provides more explicit identifiers for each status
code, such as HTTP_400_BAD_REQUEST in the status module. It's a good idea to use these throughout rather
than using numeric identifiers.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 1/6
9/20/2019 2 - Requests and responses - Django REST framework
These wrappers provide a few bits of functionality such as making sure you receive Request instances in
your view, and adding context to Response objects so that content negotiation can be performed.
The wrappers also provide behaviour such as returning 405 Method Not Allowed responses when
appropriate, and handling any ParseError exception that occurs when accessing request.data with
malformed input.
We don't need our JSONResponse class in views.py any more, so go ahead and delete that. Once that's
done we can start refactoring our views slightly.
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
Our instance view is an improvement over the previous example. It's a little more concise, and the code now
feels very similar to if we were working with the Forms API. We're also using named status codes, which
makes the response meanings more obvious.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 2/6
9/20/2019 2 - Requests and responses - Django REST framework
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
This should all feel very familiar - it is not a lot different from working with regular Django views.
Notice that we're no longer explicitly tying our requests or responses to a given content type. request.data
can handle incoming json requests, but it can also handle other formats. Similarly we're returning response
objects with data, but allowing REST framework to render the response into the correct content type for us.
Start by adding a format keyword argument to both of the views, like so.
and
Now update the snippets/urls.py file slightly, to append a set of format_suffix_patterns in addition to the
existing URLs.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 3/6
9/20/2019 2 - Requests and responses - Django REST framework
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)
We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to
a specific format.
How's it looking?
Go ahead and test the API from the command line, as we did in tutorial part 1. Everything is working pretty
similarly, although we've got some nicer error handling if we send invalid requests.
http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
...
[
{
"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 response that we get back, either by using the Accept header:
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 4/6
9/20/2019 2 - Requests and responses - Django REST framework
Similarly, we can control the format of the request that we send, using the Content-Type header.
{
"id": 3,
"title": "",
"code": "print(123)",
"linenos": false,
"language": "python",
"style": "friendly"
}
{
"id": 4,
"title": "",
"code": "print(456)",
"linenos": false,
"language": "python",
"style": "friendly"
}
If you add a --debug switch to the http requests above, you will be able to see the request type in request
headers.
Browsability
Because the API chooses the content type of the response based on the client request, it will, by default,
return an HTML-formatted representation of the resource when that resource is requested by a web browser.
This allows for the API to return a fully web-browsable HTML representation.
Having a web-browsable API is a huge usability win, and makes developing and using your API much easier.
It also dramatically lowers the barrier-to-entry for other developers wanting to inspect and work with your API.
See the browsable api topic for more information about the browsable API feature and how to customize it.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 5/6
9/20/2019 2 - Requests and responses - Django REST framework
What's next?
In tutorial part 3, we'll start using class-based views, and see how generic views reduce the amount of code
we need to write.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/ 6/6