diff options
| author | James Rutherford | 2015-03-11 10:38:03 +0000 | 
|---|---|---|
| committer | James Rutherford | 2015-03-11 10:38:03 +0000 | 
| commit | 4a2d27975ab5249269aebafd803be87a2107092b (patch) | |
| tree | 55b524c93b02eef404304f734be98871bbb1324f /docs/tutorial/2-requests-and-responses.md | |
| parent | 856dc855c952746f566a6a8de263afe951362dfb (diff) | |
| parent | dc56e5a0f41fdd6350e91a5749023d086bd1640f (diff) | |
| download | django-rest-framework-4a2d27975ab5249269aebafd803be87a2107092b.tar.bz2 | |
Merge pull request #1 from tomchristie/master
Merge in from upstream
Diffstat (limited to 'docs/tutorial/2-requests-and-responses.md')
| -rw-r--r-- | docs/tutorial/2-requests-and-responses.md | 98 | 
1 files changed, 65 insertions, 33 deletions
| diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md index 30966a10..e2c173d6 100644 --- a/docs/tutorial/2-requests-and-responses.md +++ b/docs/tutorial/2-requests-and-responses.md @@ -5,10 +5,10 @@ Let's introduce a couple of essential building blocks.  ## 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. +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. +    request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.  ## Response objects @@ -29,13 +29,13 @@ REST framework provides two wrappers you can use to write API views.  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. +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.  ## Pulling it all together -Okay, let's go ahead and start using these new components to write a few views.  +Okay, let's go ahead and start using these new components to write a few views. -We don't need our `JSONResponse` class anymore, so go ahead and delete that.  Once that's done we can start refactoring our views slightly. +We don't need our `JSONResponse` class in `views.py` anymore, so go ahead and delete that.  Once that's done we can start refactoring our views slightly.      from rest_framework import status      from rest_framework.decorators import api_view @@ -55,22 +55,21 @@ We don't need our `JSONResponse` class anymore, so go ahead and delete that.  On              return Response(serializer.data)          elif request.method == 'POST': -            serializer = SnippetSerializer(data=request.DATA) +            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) +            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  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. -Here is the view for an individual snippet. +Here is the view for an individual snippet, in the `views.py` module.      @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: @@ -81,12 +80,11 @@ Here is the view for an individual snippet.              return Response(serializer.data)          elif request.method == 'PUT': -            serializer = SnippetSerializer(snippet, data=request.DATA) +            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) +            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)          elif request.method == 'DELETE':              snippet.delete() @@ -94,11 +92,11 @@ Here is the view for an individual snippet.  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 `yaml` and 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. +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.  ## Adding optional format suffixes to our URLs -To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints.  Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as [http://example.com/api/items/4.json][json-url]. +To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints.  Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as [http://example.com/api/items/4/.json][json-url].  Start by adding a `format` keyword argument to both of the views, like so. @@ -112,12 +110,13 @@ Now update the `urls.py` file slightly, to append a set of `format_suffix_patter      from django.conf.urls import patterns, url      from rest_framework.urlpatterns import format_suffix_patterns +    from snippets import views + +    urlpatterns = [ +        url(r'^snippets/$', views.snippet_list), +        url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail), +    ] -    urlpatterns = patterns('snippets.views', -        url(r'^snippets/$', 'snippet_list'), -        url(r'^snippets/(?P<pk>[0-9]+)$', '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. @@ -128,31 +127,64 @@ Go ahead and test the API from the command line, as we did in [tutorial part 1][  We can get a list of all of the snippets, 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"}] +    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: -    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 +    http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON +    http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML  Or by appending a format suffix: -    curl http://127.0.0.1:8000/snippets/.json  # JSON suffix -    curl http://127.0.0.1:8000/snippets/.api   # Browsable API suffix +    http http://127.0.0.1:8000/snippets/.json  # JSON suffix +    http http://127.0.0.1:8000/snippets/.api   # Browsable API suffix  Similarly, we can control the format of the request that we send, using the `Content-Type` header.      # POST using form data -    curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123" +    http --form POST http://127.0.0.1:8000/snippets/ 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": 3, +      "title": "", +      "code": "print 123", +      "linenos": false, +      "language": "python", +      "style": "friendly" +    } -    {"id": 4, "title": "", "code": "print 456", "linenos": true, "language": "python", "style": "friendly"} +    # POST using JSON +    http --json POST http://127.0.0.1:8000/snippets/ code="print 456" + +    { +        "id": 4, +        "title": "", +        "code": "print 456", +        "linenos": false, +        "language": "python", +        "style": "friendly" +    }  Now go and open the API in a web browser, by visiting [http://127.0.0.1:8000/snippets/][devserver]. | 
