From a540acdc9552bcaf704371c3e1dee216059a221e Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 25 Jan 2018 09:39:03 +0100 Subject: [PATCH] Allowed customising API documentation code samples (#5752) * Allowed additional languages in API documentation * Documented renderer_classes parameter and customising languages. --- docs/topics/documenting-your-api.md | 30 ++++++++++++++++--- rest_framework/documentation.py | 11 +++++-- rest_framework/renderers.py | 2 ++ .../rest_framework/docs/document.html | 6 ++-- .../templates/rest_framework/docs/index.html | 1 + .../docs/langs/shell-intro.html | 2 +- .../rest_framework/docs/langs/shell.html | 2 +- .../templates/rest_framework/docs/link.html | 6 ++-- .../rest_framework/docs/sidebar.html | 8 ++--- 9 files changed, 49 insertions(+), 19 deletions(-) diff --git a/docs/topics/documenting-your-api.md b/docs/topics/documenting-your-api.md index fff6c4452..ff27ba353 100644 --- a/docs/topics/documenting-your-api.md +++ b/docs/topics/documenting-your-api.md @@ -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` @@ -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` @@ -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 @@ -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`: @@ -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 diff --git a/rest_framework/documentation.py b/rest_framework/documentation.py index 8aee5c932..3a78bb341 100644 --- a/rest_framework/documentation.py +++ b/rest_framework/documentation.py @@ -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, @@ -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, @@ -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( diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 304b2e292..14a371852 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -830,6 +830,8 @@ class DocumentationRenderer(BaseRenderer): 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 } diff --git a/rest_framework/templates/rest_framework/docs/document.html b/rest_framework/templates/rest_framework/docs/document.html index 7922142f3..9aecb40e0 100644 --- a/rest_framework/templates/rest_framework/docs/document.html +++ b/rest_framework/templates/rest_framework/docs/document.html @@ -8,9 +8,9 @@ {% endif %}
- {% 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 %}
{% if document|data %} diff --git a/rest_framework/templates/rest_framework/docs/index.html b/rest_framework/templates/rest_framework/docs/index.html index 9b7bb85d0..de704ab51 100644 --- a/rest_framework/templates/rest_framework/docs/index.html +++ b/rest_framework/templates/rest_framework/docs/index.html @@ -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'); diff --git a/rest_framework/templates/rest_framework/docs/langs/shell-intro.html b/rest_framework/templates/rest_framework/docs/langs/shell-intro.html index fa77bce4a..2320ddfa9 100644 --- a/rest_framework/templates/rest_framework/docs/langs/shell-intro.html +++ b/rest_framework/templates/rest_framework/docs/langs/shell-intro.html @@ -1,3 +1,3 @@ {% load rest_framework %} -
{% code bash %}# Install the command line client
+
{% code bash %}# Install the command line client
 $ pip install coreapi-cli{% endcode %}
diff --git a/rest_framework/templates/rest_framework/docs/langs/shell.html b/rest_framework/templates/rest_framework/docs/langs/shell.html index d2744920c..24137e4ae 100644 --- a/rest_framework/templates/rest_framework/docs/langs/shell.html +++ b/rest_framework/templates/rest_framework/docs/langs/shell.html @@ -1,5 +1,5 @@ {% load rest_framework %} -
{% code bash %}# Load the schema document
+
{% code bash %}# Load the schema document
 $ coreapi get {{ document.url }}{% if schema_format %} --format {{ schema_format }}{% endif %}
 
 # Interact with the API endpoint
diff --git a/rest_framework/templates/rest_framework/docs/link.html b/rest_framework/templates/rest_framework/docs/link.html
index fc2320a5f..c40a44733 100644
--- a/rest_framework/templates/rest_framework/docs/link.html
+++ b/rest_framework/templates/rest_framework/docs/link.html
@@ -93,9 +93,9 @@
 
 
     
- {% 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 %}
diff --git a/rest_framework/templates/rest_framework/docs/sidebar.html b/rest_framework/templates/rest_framework/docs/sidebar.html index d23787025..c318789f6 100644 --- a/rest_framework/templates/rest_framework/docs/sidebar.html +++ b/rest_framework/templates/rest_framework/docs/sidebar.html @@ -31,12 +31,12 @@