mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-07 22:04:48 +03:00
Initial schema generation & first tutorial 7 draft
This commit is contained in:
parent
6c60f58a56
commit
b7fcdd257e
|
@ -130,27 +130,7 @@ Using viewsets can be a really useful abstraction. It helps ensure that URL con
|
|||
|
||||
That doesn't mean it's always the right approach to take. There's a similar set of trade-offs to consider as when using class-based views instead of function based views. Using viewsets is less explicit than building your views individually.
|
||||
|
||||
## Reviewing our work
|
||||
In [part 7][tut-7] of the tutorial we'll look at how we can add an API schema,
|
||||
and interact with our API using a client library or command line tool.
|
||||
|
||||
With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, and comes complete with authentication, per-object permissions, and multiple renderer formats.
|
||||
|
||||
We've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.
|
||||
|
||||
You can review the final [tutorial code][repo] on GitHub, or try out a live example in [the sandbox][sandbox].
|
||||
|
||||
## Onwards and upwards
|
||||
|
||||
We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:
|
||||
|
||||
* Contribute on [GitHub][github] by reviewing and submitting issues, and making pull requests.
|
||||
* Join the [REST framework discussion group][group], and help build the community.
|
||||
* Follow [the author][twitter] on Twitter and say hi.
|
||||
|
||||
**Now go build awesome things.**
|
||||
|
||||
|
||||
[repo]: https://github.com/tomchristie/rest-framework-tutorial
|
||||
[sandbox]: http://restframework.herokuapp.com/
|
||||
[github]: https://github.com/tomchristie/django-rest-framework
|
||||
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
|
||||
[twitter]: https://twitter.com/_tomchristie
|
||||
[tut-7]: 7-schemas-and-client-libraries.md
|
||||
|
|
|
@ -90,45 +90,127 @@ First we'll load the API schema using the command line client.
|
|||
$ coreapi get http://127.0.0.1:8000/
|
||||
<Pastebin API "http://127.0.0.1:8000/">
|
||||
snippets: {
|
||||
create(code, [title], [linenos], [language], [style])
|
||||
destroy(id)
|
||||
highlight(id)
|
||||
highlight(pk)
|
||||
list()
|
||||
partial_update(id, [title], [code], [linenos], [language], [style])
|
||||
retrieve(id)
|
||||
update(id, code, [title], [linenos], [language], [style])
|
||||
retrieve(pk)
|
||||
}
|
||||
users: {
|
||||
list()
|
||||
retrieve(id)
|
||||
retrieve(pk)
|
||||
}
|
||||
|
||||
At this point we're able to see all the available API endpoints.
|
||||
We haven't authenticated yet, so right now we're only able to see the read only
|
||||
endpoints, in line with how we've set up the permissions on the API.
|
||||
|
||||
We can now interact with the API using the command line client:
|
||||
Let's try listing the existing snippets, using the command line client:
|
||||
|
||||
$ coreapi action list_snippets
|
||||
$ coreapi action snippets list
|
||||
[
|
||||
{
|
||||
"url": "http://127.0.0.1:8000/snippets/1/",
|
||||
"highlight": "http://127.0.0.1:8000/snippets/1/highlight/",
|
||||
"owner": "lucy",
|
||||
"title": "Example",
|
||||
"code": "print('hello, world!')",
|
||||
"linenos": true,
|
||||
"language": "python",
|
||||
"style": "friendly"
|
||||
},
|
||||
...
|
||||
|
||||
Some of the API endpoints require named parameters. For example, to get back
|
||||
the hightlight HTML for a particular snippet we need to provide an id.
|
||||
|
||||
$ coreapi action snippets highlight --param pk 1
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Example</title>
|
||||
...
|
||||
|
||||
## Authenticating our client
|
||||
|
||||
TODO - authentication
|
||||
If we want to be able to create and edit snippets, we'll need to authenticate
|
||||
as a valid user. In this case we'll just use basic auth.
|
||||
|
||||
$ coreapi action snippets create --param code "print('hello, world')"
|
||||
Make sure to replace the `<username>` and `<password>` below with your
|
||||
actual username and password.
|
||||
|
||||
$ coreapi credentials add 127.0.0.1 <username>:<password> --auth basic
|
||||
Added credentials
|
||||
127.0.0.1 "Basic <...>"
|
||||
|
||||
## Using a client library
|
||||
Now if we fetch the schema again, we should be able to see the full
|
||||
set of available interactions.
|
||||
|
||||
*TODO - document using python client library, rather than the command line tool.*
|
||||
$ coreapi reload
|
||||
Pastebin API "http://127.0.0.1:8000/">
|
||||
snippets: {
|
||||
create(code, [title], [linenos], [language], [style])
|
||||
destroy(pk)
|
||||
highlight(pk)
|
||||
list()
|
||||
partial_update(pk, [title], [code], [linenos], [language], [style])
|
||||
retrieve(pk)
|
||||
update(pk, code, [title], [linenos], [language], [style])
|
||||
}
|
||||
users: {
|
||||
list()
|
||||
retrieve(pk)
|
||||
}
|
||||
|
||||
## Using another schema format
|
||||
We're now able to interact with these endpoints. For example, to create a new
|
||||
snippet:
|
||||
|
||||
*TODO - document using OpenAPI instead.*
|
||||
$ coreapi action snippets create --param title "Example" --param code "print('hello, world')"
|
||||
{
|
||||
"url": "http://127.0.0.1:8000/snippets/7/",
|
||||
"id": 7,
|
||||
"highlight": "http://127.0.0.1:8000/snippets/7/highlight/",
|
||||
"owner": "lucy",
|
||||
"title": "Example",
|
||||
"code": "print('hello, world')",
|
||||
"linenos": false,
|
||||
"language": "python",
|
||||
"style": "friendly"
|
||||
}
|
||||
|
||||
## Customizing schema generation
|
||||
And to delete a snippet:
|
||||
|
||||
*TODO - document writing an explict schema view.*
|
||||
$ coreapi action snippets destroy --param pk 7
|
||||
|
||||
As well as the command line client, developers can also interact with your
|
||||
API using client libraries. The Python client library is the first of these
|
||||
to be available, and a Javascript client library is planned to be released
|
||||
soon.
|
||||
|
||||
For more details on customizing schema generation and using Core API
|
||||
client libraries you'll need to refer to the full documentation.
|
||||
|
||||
## Reviewing our work
|
||||
|
||||
With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, includes a schema-driven client library, and comes complete with authentication, per-object permissions, and multiple renderer formats.
|
||||
|
||||
We've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.
|
||||
|
||||
You can review the final [tutorial code][repo] on GitHub, or try out a live example in [the sandbox][sandbox].
|
||||
|
||||
## Onwards and upwards
|
||||
|
||||
We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:
|
||||
|
||||
* Contribute on [GitHub][github] by reviewing and submitting issues, and making pull requests.
|
||||
* Join the [REST framework discussion group][group], and help build the community.
|
||||
* Follow [the author][twitter] on Twitter and say hi.
|
||||
|
||||
**Now go build awesome things.**
|
||||
|
||||
[coreapi]: http://www.coreapi.org
|
||||
[corejson]: http://www.coreapi.org/specification/encoding/#core-json-encoding
|
||||
[openapi]: https://openapis.org/
|
||||
[repo]: https://github.com/tomchristie/rest-framework-tutorial
|
||||
[sandbox]: http://restframework.herokuapp.com/
|
||||
[github]: https://github.com/tomchristie/django-rest-framework
|
||||
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
|
||||
[twitter]: https://twitter.com/_tomchristie
|
||||
|
|
|
@ -23,8 +23,9 @@ from django.conf.urls import url
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import NoReverseMatch
|
||||
|
||||
from rest_framework import renderers, views
|
||||
from rest_framework import exceptions, renderers, views
|
||||
from rest_framework.compat import coreapi
|
||||
from rest_framework.request import override_method
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.settings import api_settings
|
||||
|
@ -262,7 +263,7 @@ class SimpleRouter(BaseRouter):
|
|||
|
||||
return ret
|
||||
|
||||
def get_links(self):
|
||||
def get_links(self, request=None):
|
||||
content = {}
|
||||
|
||||
for prefix, viewset, basename in self.registry:
|
||||
|
@ -284,13 +285,23 @@ class SimpleRouter(BaseRouter):
|
|||
continue
|
||||
|
||||
for method, action in mapping.items():
|
||||
link = self.get_link(viewset, url, method, request)
|
||||
if link is None:
|
||||
continue # User does not have permissions.
|
||||
if prefix not in content:
|
||||
content[prefix] = {}
|
||||
link = self.get_link(viewset, url, method)
|
||||
content[prefix][action] = link
|
||||
return content
|
||||
|
||||
def get_link(self, viewset, url, method):
|
||||
def get_link(self, viewset, url, method, request=None):
|
||||
view_instance = viewset()
|
||||
if request is not None:
|
||||
with override_method(view_instance, request, method.upper()) as request:
|
||||
try:
|
||||
view_instance.check_permissions(request)
|
||||
except exceptions.APIException as exc:
|
||||
return None
|
||||
|
||||
fields = []
|
||||
|
||||
for variable in uritemplate.variables(url):
|
||||
|
@ -298,7 +309,7 @@ class SimpleRouter(BaseRouter):
|
|||
fields.append(field)
|
||||
|
||||
if method in ('put', 'patch', 'post'):
|
||||
cls = viewset().get_serializer_class()
|
||||
cls = view_instance.get_serializer_class()
|
||||
serializer = cls()
|
||||
for field in serializer.fields.values():
|
||||
if field.read_only:
|
||||
|
@ -336,9 +347,8 @@ class DefaultRouter(SimpleRouter):
|
|||
|
||||
if self.schema_title:
|
||||
assert coreapi, '`coreapi` must be installed for schema support.'
|
||||
content = self.get_links()
|
||||
schema = coreapi.Document(title=self.schema_title, content=content)
|
||||
view_renderers += [renderers.CoreJSONRenderer]
|
||||
router = self
|
||||
|
||||
class APIRoot(views.APIView):
|
||||
_ignore_model_permissions = True
|
||||
|
@ -346,6 +356,10 @@ class DefaultRouter(SimpleRouter):
|
|||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.accepted_renderer.format == 'corejson':
|
||||
content = router.get_links(request)
|
||||
if not content:
|
||||
raise exceptions.PermissionDenied()
|
||||
schema = coreapi.Document(title=router.schema_title, content=content)
|
||||
return Response(schema)
|
||||
|
||||
ret = OrderedDict()
|
||||
|
|
Loading…
Reference in New Issue
Block a user