Updating docs

This commit is contained in:
Tom Christie 2012-09-12 10:12:13 +01:00
parent d4f8b4cf06
commit c85f799ade
13 changed files with 260 additions and 31 deletions

View File

@ -2,6 +2,10 @@
# Authentication # Authentication
> Auth needs to be pluggable.
>
> — Jacob Kaplan-Moss, ["REST worst practices"][cite]
Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The [permission] and [throttling] policies can then use those credentials to determine if the request should be permitted. Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The [permission] and [throttling] policies can then use those credentials to determine if the request should be permitted.
REST framework provides a number of authentication policies out of the box, and also allows you to implement custom policies. REST framework provides a number of authentication policies out of the box, and also allows you to implement custom policies.
@ -60,7 +64,7 @@ Or, if you're using the `@api_view` decorator with function based views.
This policy uses [HTTP Basic Authentication][basicauth], signed against a user's username and password. User basic authentication is generally only appropriate for testing. This policy uses [HTTP Basic Authentication][basicauth], signed against a user's username and password. User basic authentication is generally only appropriate for testing.
**Note:** If you run `UserBasicAuthentication` in production your API must be `https` only, or it will be completely insecure. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage. **Note:** If you run `UserBasicAuthentication` in production your API should be `https` only. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
If successfully authenticated, `UserBasicAuthentication` provides the following credentials. If successfully authenticated, `UserBasicAuthentication` provides the following credentials.
@ -69,11 +73,13 @@ If successfully authenticated, `UserBasicAuthentication` provides the following
## TokenAuthentication ## TokenAuthentication
This policy uses [HTTP Authentication][basicauth] with no authentication scheme. Token basic authentication is appropriate for client-server setups, such as native desktop and mobile clients. The token key should be passed in as a string to the "Authorization" HTTP header. For example: This policy uses simple token-based HTTP Authentication. Token basic authentication is appropriate for client-server setups, such as native desktop and mobile clients.
The token key should be passed in as a string to the "Authorization" HTTP header. For example:
curl http://my.api.org/ -X POST -H "Authorization: 0123456789abcdef0123456789abcdef" curl http://my.api.org/ -X POST -H "Authorization: 0123456789abcdef0123456789abcdef"
**Note:** If you run `TokenAuthentication` in production your API must be `https` only, or it will be completely insecure. **Note:** If you run `TokenAuthentication` in production your API should be `https` only.
If successfully authenticated, `TokenAuthentication` provides the following credentials. If successfully authenticated, `TokenAuthentication` provides the following credentials.
@ -102,8 +108,9 @@ If successfully authenticated, `SessionAuthentication` provides the following cr
## Custom authentication policies ## Custom authentication policies
To implement a custom authentication policy, subclass `BaseAuthentication` and override the `authenticate(self, request)` method. The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise. To implement a custom authentication policy, subclass `BaseAuthentication` and override the `.authenticate(self, request)` method. The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise.
[cite]: http://jacobian.org/writing/rest-worst-practices/
[basicauth]: http://tools.ietf.org/html/rfc2617 [basicauth]: http://tools.ietf.org/html/rfc2617
[oauth]: http://oauth.net/2/ [oauth]: http://oauth.net/2/
[permission]: permissions.md [permission]: permissions.md

View File

@ -0,0 +1,7 @@
# Content negotiation
> HTTP has provisions for several mechanisms for "content negotiation" - the process of selecting the best representation for a given response when there are multiple representations available.
>
> — [RFC 2616][cite], Fielding et al.
[cite]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html

View File

@ -1 +0,0 @@
> HTTP has provisions for several mechanisms for "content negotiation" -- the process of selecting the best representation for a given response when there are multiple representations available. -- RFC 2616, Fielding et al.

View File

@ -2,4 +2,83 @@
# Exceptions # Exceptions
> Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.
>
> — Doug Hellmann, [Python Exception Handling Techniques][cite]
## Exception handling in REST framework views
REST framework's views handle various exceptions, and deal with returning appropriate error responses for you.
The handled exceptions are:
* Subclasses of `APIException` raised inside REST framework.
* Django's `Http404` exception.
* Django's `PermissionDenied` exception.
In each case, REST framework will return a response, rendering it to an appropriate content-type.
By default all error messages will include a key `details` in the body of the response, but other keys may also be included.
For example, the following request:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
Might recieve an error response indicating that the `DELETE` method is not allowed on that resource:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=utf-8
Content-Length: 42
{"detail": "Method 'DELETE' not allowed."}
## APIException
**Signature:** `APIException(detail=None)`
The base class for all exceptions raised inside REST framework.
To provide a custom exception, subclass `APIException` and set the `.status_code` and `.detail` properties on the class.
## ParseError
**Signature:** `ParseError(detail=None)`
Raised if the request contains malformed data when accessing `request.DATA` or `request.FILES`.
By default this exception results in a response with the HTTP status code "400 Bad Request".
## PermissionDenied
**Signature:** `PermissionDenied(detail=None)`
Raised when an incoming request fails the permission checks.
By default this exception results in a response with the HTTP status code "403 Forbidden".
## MethodNotAllowed
**Signature:** `MethodNotAllowed(method, detail=None)`
Raised when an incoming request occurs that does not map to a handler method on the view.
By default this exception results in a response with the HTTP status code "405 Method Not Allowed".
## UnsupportedMediaType
**Signature:** `UnsupportedMediaType(media_type, detail=None)`
Raised if there are no parsers that can handle the content type of the request data when accessing `request.DATA` or `request.FILES`.
By default this exception results in a response with the HTTP status code "415 Unsupported Media Type".
## Throttled
**Signature:** `Throttled(wait=None, detail=None)`
Raised when an incoming request fails the throttling checks.
By default this exception results in a response with the HTTP status code "429 Too Many Requests".
[cite]: http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html

View File

@ -0,0 +1,11 @@
<a class="github" href="urlpatterns.py"></a>
# Format suffixes
> Section 6.2.1 does not say that content negotiation should be
used all the time.
>
> &mdash; Roy Fielding, [REST discuss mailing list][cite]
[cite]: http://tech.groups.yahoo.com/group/rest-discuss/message/5857

View File

@ -0,0 +1,10 @@
<a class="github" href="mixins.py"></a>
<a class="github" href="generics.py"></a>
# Generic views
> Djangos generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself.
>
> &mdash; [Django Documentation][cite]
[cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views

View File

@ -1,3 +1,87 @@
<a class="github" href="permissions.py"></a> <a class="github" href="permissions.py"></a>
# Permissions # Permissions
> Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.
>
> &mdash; [Apple Developer Documentation][cite]
Together with [authentication] and [throttling], permissions determine wheter a request should be granted or denied access.
Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the `request.user` and `request.auth` properties to determine if the incoming request should be permitted.
## How permissions are determined
Permissions in REST framework are always defined as a list of permission classes. Before running the main body of the view, each permission in the list is checked.
If any permission check fails an `exceptions.PermissionDenied` exception will be raised, and the main body of the view will not run.
## Object level permissions
REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.
Object level permissions are run by REST framework's generic views when `.get_object()` is called. As with view level permissions, an `exceptions.PermissionDenied` exception will be raised if the user is not allowed to act on the given object.
## Setting the permission policy
The default permission policy may be set globally, using the `DEFAULT_PERMISSIONS` setting. For example.
API_SETTINGS = {
'DEFAULT_PERMISSIONS': (
'djangorestframework.permissions.IsAuthenticated',
)
}
You can also set the authentication policy on a per-view basis, using the `APIView` class based views.
class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Or, if you're using the `@api_view` decorator with function based views.
@api_view('GET')
@permission_classes(IsAuthenticated)
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
## IsAuthenticated
The `IsAuthenticated` permission class will deny permission to any unauthenticated user, and allow permission otherwise.
This permission is suitable if you want your API to only be accessible to registered users.
## IsAdminUser
The `IsAdminUser` permission class will deny permission to any user, unless `user.is_staff`is `True` in which case permission will be allowed.
This permission is suitable is you want your API to only be accessible to a subset of trusted administrators.
## IsAuthenticatedOrReadOnly
The `IsAuthenticatedOrReadOnly` will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the "safe" methods; `GET`, `HEAD` or `OPTIONS`.
This permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.
## DjangoModelPermissions
This permission class ties into Django's standard `django.contrib.auth` model permissions. When applied to a view that has a `.model` property, permission will only be granted if the user
## Custom permissions
To implement a custom permission, override `BasePermission` and implement the `.check_permission(self, request, obj=None)` method.
The method should return `True` if the request should be granted access, and `False` otherwise.
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
[authentication]: authentication.md
[throttling]: throttling.md

View File

@ -1,12 +1,12 @@
<a class="github" href="reverse.py"></a> <a class="github" href="reverse.py"></a>
# Returning URIs from your Web APIs # Returning URLs
> The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components. > The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components.
> >
> &mdash; Roy Fielding, [Architectural Styles and the Design of Network-based Software Architectures][cite] > &mdash; Roy Fielding, [Architectural Styles and the Design of Network-based Software Architectures][cite]
As a rule, it's probably better practice to return absolute URIs from you web APIs, such as `http://example.com/foobar`, rather than returning relative URIs, such as `/foobar`. As a rule, it's probably better practice to return absolute URIs from you Web APIs, such as `http://example.com/foobar`, rather than returning relative URIs, such as `/foobar`.
The advantages of doing so are: The advantages of doing so are:

View File

@ -2,9 +2,13 @@
# Settings # Settings
Configuration for REST framework is all namespaced inside the `API_SETTINGS` setting. > Namespaces are one honking great idea - let's do more of those!
>
> &mdash; [The Zen of Python][cite]
For example your project's `settings.py` file might look like this: Configuration for REST framework is all namespaced inside a single Django setting, named `API_SETTINGS`.
For example your project's `settings.py` file might include something like this:
API_SETTINGS = { API_SETTINGS = {
'DEFAULT_RENDERERS': ( 'DEFAULT_RENDERERS': (
@ -133,3 +137,5 @@ The name of a URL parameter that may be used to override the HTTP `Accept` heade
If the value of this setting is `None` then URL accept overloading will be disabled. If the value of this setting is `None` then URL accept overloading will be disabled.
Default: `'_accept'` Default: `'_accept'`
[cite]: http://www.python.org/dev/peps/pep-0020/

View File

@ -1,3 +1,15 @@
<a class="github" href="throttling.py"></a> <a class="github" href="throttling.py"></a>
# Throttling # Throttling
> HTTP/1.1 420 Enhance Your Calm
>
> [Twitter API rate limiting response][cite]
[cite]: https://dev.twitter.com/docs/error-codes-responses
## PerUserThrottle
## PerViewThrottle
## Custom throttles

View File

@ -77,15 +77,18 @@ The API guide is your complete reference manual to all the functionality provide
* [Requests][request] * [Requests][request]
* [Responses][response] * [Responses][response]
* [Views][views] * [Views][views]
* [Generic views][generic-views]
* [Parsers][parsers] * [Parsers][parsers]
* [Renderers][renderers] * [Renderers][renderers]
* [Serializers][serializers] * [Serializers][serializers]
* [Authentication][authentication] * [Authentication][authentication]
* [Permissions][permissions] * [Permissions][permissions]
* [Throttling][throttling] * [Throttling][throttling]
* [Content negotiation][contentnegotiation]
* [Format suffixes][formatsuffixes]
* [Returning URLs][reverse]
* [Exceptions][exceptions] * [Exceptions][exceptions]
* [Status codes][status] * [Status codes][status]
* [Returning URLs][reverse]
* [Settings][settings] * [Settings][settings]
## Topics ## Topics
@ -149,15 +152,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[request]: api-guide/requests.md [request]: api-guide/requests.md
[response]: api-guide/responses.md [response]: api-guide/responses.md
[views]: api-guide/views.md [views]: api-guide/views.md
[generic-views]: api-guide/generic-views.md
[parsers]: api-guide/parsers.md [parsers]: api-guide/parsers.md
[renderers]: api-guide/renderers.md [renderers]: api-guide/renderers.md
[serializers]: api-guide/serializers.md [serializers]: api-guide/serializers.md
[authentication]: api-guide/authentication.md [authentication]: api-guide/authentication.md
[permissions]: api-guide/permissions.md [permissions]: api-guide/permissions.md
[throttling]: api-guide/throttling.md [throttling]: api-guide/throttling.md
[contentnegotiation]: api-guide/content-negotiation.md
[formatsuffixes]: api-guide/format-suffixes.md
[reverse]: api-guide/reverse.md
[exceptions]: api-guide/exceptions.md [exceptions]: api-guide/exceptions.md
[status]: api-guide/status-codes.md [status]: api-guide/status-codes.md
[reverse]: api-guide/reverse.md
[settings]: api-guide/settings.md [settings]: api-guide/settings.md
[csrf]: topics/csrf.md [csrf]: topics/csrf.md

View File

@ -14,15 +14,6 @@ pre {
font-size: 12px; font-size: 12px;
} }
a.github {
float: right;
margin-top: -12px;
}
a.github:hover {
text-decoration: none;
}
.dropdown .dropdown-menu { .dropdown .dropdown-menu {
display: none; display: none;
} }
@ -31,25 +22,38 @@ a.github:hover {
display: block; display: block;
} }
/* GitHub 'Star' badge */
body.index #main-content iframe { body.index #main-content iframe {
float: right; float: right;
} margin-top: -12px;
body.index #main-content iframe {
float: right;
margin-right: -15px; margin-right: -15px;
} }
/* Travis CI badge */
body.index #main-content p:first-of-type { body.index #main-content p:first-of-type {
float: right; float: right;
margin-right: 8px; margin-right: 8px;
margin-top: -1px; margin-top: -14px;
margin-bottom: 0px;
} }
/* Github source file badges */
a.github {
float: right;
margin-top: -12px;
margin-right: 12px;
}
a.github:hover {
text-decoration: none;
}
/* Force TOC text to not overrun */
#table-of-contents { #table-of-contents {
overflow: hidden; overflow: hidden;
} }
/* Code blocks should scroll horizontally */
pre { pre {
overflow: auto; overflow: auto;
word-wrap: normal; word-wrap: normal;
@ -71,13 +75,10 @@ pre {
} }
} }
.nav-list li.main { .nav-list li.main {
font-weight: bold; font-weight: bold;
} }
/* Set the table of contents to static so it flows back into the content when /* Set the table of contents to static so it flows back into the content when
viewed on tablets and smaller. */ viewed on tablets and smaller. */
@media (max-width: 767px) { @media (max-width: 767px) {
@ -94,7 +95,7 @@ pre {
} }
} }
/* Cutesy quote styling */
blockquote { blockquote {
font-family: Georgia, serif; font-family: Georgia, serif;
font-size: 18px; font-size: 18px;

View File

@ -47,15 +47,18 @@
<li><a href="{{ base_url }}/api-guide/requests{{ suffix }}">Requests</a></li> <li><a href="{{ base_url }}/api-guide/requests{{ suffix }}">Requests</a></li>
<li><a href="{{ base_url }}/api-guide/responses{{ suffix }}">Responses</a></li> <li><a href="{{ base_url }}/api-guide/responses{{ suffix }}">Responses</a></li>
<li><a href="{{ base_url }}/api-guide/views{{ suffix }}">Views</a></li> <li><a href="{{ base_url }}/api-guide/views{{ suffix }}">Views</a></li>
<li><a href="{{ base_url }}/api-guide/generic-views{{ suffix }}">Generic views</a></li>
<li><a href="{{ base_url }}/api-guide/parsers{{ suffix }}">Parsers</a></li> <li><a href="{{ base_url }}/api-guide/parsers{{ suffix }}">Parsers</a></li>
<li><a href="{{ base_url }}/api-guide/renderers{{ suffix }}">Renderers</a></li> <li><a href="{{ base_url }}/api-guide/renderers{{ suffix }}">Renderers</a></li>
<li><a href="{{ base_url }}/api-guide/serializers{{ suffix }}">Serializers</a></li> <li><a href="{{ base_url }}/api-guide/serializers{{ suffix }}">Serializers</a></li>
<li><a href="{{ base_url }}/api-guide/authentication{{ suffix }}">Authentication</a></li> <li><a href="{{ base_url }}/api-guide/authentication{{ suffix }}">Authentication</a></li>
<li><a href="{{ base_url }}/api-guide/permissions{{ suffix }}">Permissions</a></li> <li><a href="{{ base_url }}/api-guide/permissions{{ suffix }}">Permissions</a></li>
<li><a href="{{ base_url }}/api-guide/throttling{{ suffix }}">Throttling</a></li> <li><a href="{{ base_url }}/api-guide/throttling{{ suffix }}">Throttling</a></li>
<li><a href="{{ base_url }}/api-guide/content-negotiation{{ suffix }}">Content negotiation</a></li>
<li><a href="{{ base_url }}/api-guide/format-suffixes{{ suffix }}">Format suffixes</a></li>
<li><a href="{{ base_url }}/api-guide/reverse{{ suffix }}">Returning URLs</a></li>
<li><a href="{{ base_url }}/api-guide/exceptions{{ suffix }}">Exceptions</a></li> <li><a href="{{ base_url }}/api-guide/exceptions{{ suffix }}">Exceptions</a></li>
<li><a href="{{ base_url }}/api-guide/status-codes{{ suffix }}">Status codes</a></li> <li><a href="{{ base_url }}/api-guide/status-codes{{ suffix }}">Status codes</a></li>
<li><a href="{{ base_url }}/api-guide/reverse{{ suffix }}">Returning URLs</a></li>
<li><a href="{{ base_url }}/api-guide/settings{{ suffix }}">Settings</a></li> <li><a href="{{ base_url }}/api-guide/settings{{ suffix }}">Settings</a></li>
</ul> </ul>
</li> </li>
@ -112,5 +115,9 @@
var shiftWindow = function() { scrollBy(0, -50) }; var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow(); if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow); window.addEventListener("hashchange", shiftWindow);
$('.dropdown-menu').click(function(event) {
event.stopPropagation();
});
</script> </script>
</body></html> </body></html>