Skip to content

Allowed customising API documentation code samples #5752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions docs/topics/documenting-your-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ The `rest_framework.documentation` module provides three helper functions to hel
* `generator_class`: Default `rest_framework.schemas.SchemaGenerator`. May be used to specify a `SchemaGenerator` subclass to be passed to the `SchemaView`.
* `authentication_classes`: Default `api_settings.DEFAULT_AUTHENTICATION_CLASSES`. May be used to pass custom authentication classes to the `SchemaView`.
* `permission_classes`: Default `api_settings.DEFAULT_PERMISSION_CLASSES` May be used to pass custom permission classes to the `SchemaView`.
* `renderer_classes`: Default `None`. May be used to pass custom renderer classes to the `SchemaView`.

#### `get_docs_view`

Expand All @@ -117,7 +118,8 @@ The `rest_framework.documentation` module provides three helper functions to hel
* `patterns`: Default `None`. A list of URLs to inspect when generating the schema. If `None` project's URL conf will be used.
* `generator_class`: Default `rest_framework.schemas.SchemaGenerator`. May be used to specify a `SchemaGenerator` subclass to be passed to the `SchemaView`.
* `authentication_classes`: Default `api_settings.DEFAULT_AUTHENTICATION_CLASSES`. May be used to pass custom authentication classes to the `SchemaView`.
* `permission_classes`: Default `api_settings.DEFAULT_PERMISSION_CLASSES` May be used to pass custom permission classes to the `SchemaView`.
* `permission_classes`: Default `api_settings.DEFAULT_PERMISSION_CLASSES`. May be used to pass custom permission classes to the `SchemaView`.
* `renderer_classes`: Default `None`. May be used to pass custom renderer classes to the `SchemaView`. If `None` the `SchemaView` will be configured with `DocumentationRenderer` and `CoreJSONRenderer` renderers, corresponding to the (default) `html` and `corejson` formats.

#### `get_schemajs_view`

Expand All @@ -130,6 +132,25 @@ The `rest_framework.documentation` module provides three helper functions to hel
* `authentication_classes`: Default `api_settings.DEFAULT_AUTHENTICATION_CLASSES`. May be used to pass custom authentication classes to the `SchemaView`.
* `permission_classes`: Default `api_settings.DEFAULT_PERMISSION_CLASSES` May be used to pass custom permission classes to the `SchemaView`.


### Customising code samples

The built-in API documentation includes automatically generated code samples for
each of the available API client libraries.

You may customise these samples by subclassing `DocumentationRenderer`, setting
`languages` to the list of languages you wish to support:

from rest_framework.renderers import DocumentationRenderer


class CustomRenderer(DocumentationRenderer):
languages = ['ruby', 'go']

For each language you need to provide an `intro` template, detailing installation instructions and such,
plus a generic template for making API requests, that can be filled with individual request details.
See the [templates for the bundled languages][client-library-templates] for examples.

---

## Third party packages
Expand All @@ -138,11 +159,11 @@ There are a number of mature third-party packages for providing API documentatio

#### drf-yasg - Yet Another Swagger Generator

[drf-yasg][drf-yasg] is a [Swagger][swagger] generation tool implemented without using the schema generation provided
[drf-yasg][drf-yasg] is a [Swagger][swagger] generation tool implemented without using the schema generation provided
by Django Rest Framework.

It aims to implement as much of the [OpenAPI][open-api] specification as possible - nested schemas, named models,
response bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code
It aims to implement as much of the [OpenAPI][open-api] specification as possible - nested schemas, named models,
response bodies, enum/pattern/min/max validators, form parameters, etc. - and to generate documents usable with code
generation tools like `swagger-codegen`.

This also translates into a very useful interactive documentation viewer in the form of `swagger-ui`:
Expand Down Expand Up @@ -314,3 +335,4 @@ To implement a hypermedia API you'll need to decide on an appropriate media type
[image-self-describing-api]: ../img/self-describing.png
[schemas-examples]: ../api-guide/schemas/#example
[metadata-docs]: ../api-guide/metadata/
[client-library-templates]: https://github.com/encode/django-rest-framework/tree/master/rest_framework/templates/rest_framework/docs/langs
11 changes: 8 additions & 3 deletions rest_framework/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ def get_docs_view(
title=None, description=None, schema_url=None, public=True,
patterns=None, generator_class=SchemaGenerator,
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES,
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES):
renderer_classes = [DocumentationRenderer, CoreJSONRenderer]
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES,
renderer_classes=None):

if renderer_classes is None:
renderer_classes = [DocumentationRenderer, CoreJSONRenderer]

return get_schema_view(
title=title,
Expand Down Expand Up @@ -51,7 +54,8 @@ def include_docs_urls(
title=None, description=None, schema_url=None, public=True,
patterns=None, generator_class=SchemaGenerator,
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES,
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES):
permission_classes=api_settings.DEFAULT_PERMISSION_CLASSES,
renderer_classes=None):
docs_view = get_docs_view(
title=title,
description=description,
Expand All @@ -60,6 +64,7 @@ def include_docs_urls(
patterns=patterns,
generator_class=generator_class,
authentication_classes=authentication_classes,
renderer_classes=renderer_classes,
permission_classes=permission_classes,
)
schema_js_view = get_schemajs_view(
Expand Down
2 changes: 2 additions & 0 deletions rest_framework/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,8 @@ def get_context(self, data, request):
return {
'document': data,
'langs': self.languages,
'lang_htmls': ["rest_framework/docs/langs/%s.html" % l for l in self.languages],
'lang_intro_htmls': ["rest_framework/docs/langs/%s-intro.html" % l for l in self.languages],
'code_style': pygments_css(self.code_style),
'request': request
}
Expand Down
6 changes: 3 additions & 3 deletions rest_framework/templates/rest_framework/docs/document.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ <h1>{{ document.title }}</h1>
{% endif %}
</div>
<div class="col-md-6 intro-code">
{% if 'shell' in langs %}{% include "rest_framework/docs/langs/shell-intro.html" %}{% endif %}
{% if 'python' in langs %}{% include "rest_framework/docs/langs/python-intro.html" %}{% endif %}
{% if 'javascript' in langs %}{% include "rest_framework/docs/langs/javascript-intro.html" %}{% endif %}
{% for html in lang_intro_htmls %}
{% include html %}
{% endfor %}
</div>
</div>
{% if document|data %}
Expand Down
1 change: 1 addition & 0 deletions rest_framework/templates/rest_framework/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
$('#auth-control').children().removeClass('active');
$('#auth-control').find("[data-auth='session']").closest('li').addClass('active');
{% endif %}
$('pre.highlight').filter('[data-language="{{ langs | first }}"]').removeClass('hide');
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{% load rest_framework %}
<pre class="highlight shell" data-language="shell"><code>{% code bash %}# Install the command line client
<pre class="highlight shell hide" data-language="shell"><code>{% code bash %}# Install the command line client
$ pip install coreapi-cli{% endcode %}</code></pre>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% load rest_framework %}
<pre class="highlight shell" data-language="shell"><code>{% code bash %}# Load the schema document
<pre class="highlight shell hide" data-language="shell"><code>{% code bash %}# Load the schema document
$ coreapi get {{ document.url }}{% if schema_format %} --format {{ schema_format }}{% endif %}

# Interact with the API endpoint
Expand Down
6 changes: 3 additions & 3 deletions rest_framework/templates/rest_framework/docs/link.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ <h4>Request Body</h4>
</div>

<div class="col-md-6 code-samples">
{% if 'shell' in langs %}{% include "rest_framework/docs/langs/shell.html" %}{% endif %}
{% if 'python' in langs %}{% include "rest_framework/docs/langs/python.html" %}{% endif %}
{% if 'javascript' in langs %}{% include "rest_framework/docs/langs/javascript.html" %}{% endif %}
{% for html in lang_htmls %}
{% include html %}
{% endfor %}
</div>
</div>

Expand Down
8 changes: 4 additions & 4 deletions rest_framework/templates/rest_framework/docs/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ <h3 class="brand"><a href="#">{{ document.title }}</a></h3>
</ul>

<li data-toggle="collapse" data-target="#language-control" class="collapsed">
<a><i class="fa fa-code fa-lg"></i> Source Code</a> <span id="selected-language">shell</span>
<a><i class="fa fa-code fa-lg"></i> Source Code</a> <span id="selected-language">{{ langs | first }}</span>
</li>
<ul class="sub-menu collapse out" id="language-control">
<li class="active"><a href="#" data-language="shell">shell</a></li>
<li><a href="#" data-language="javascript">javascript</a></li>
<li><a href="#" data-language="python">python</a></li>
{% for lang in langs %}
<li{% if loop.first %} class="active"{% endif %}><a href="#" data-language="{{ lang }}">{{ lang }}</a></li>
{% endfor %}
</ul>
</ul>

Expand Down