From 061e0ed0841274da930f61838c60af1324ea04bc Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 28 Jul 2016 12:08:34 +0100 Subject: [PATCH] Added url and schema_url arguments (#4321) --- docs/api-guide/schemas.md | 20 +++++++++++++++++--- rest_framework/compat.py | 6 ++++++ rest_framework/routers.py | 12 ++++++++---- rest_framework/schemas.py | 12 ++++++++---- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/docs/api-guide/schemas.md b/docs/api-guide/schemas.md index 8abd746463..848e574208 100644 --- a/docs/api-guide/schemas.md +++ b/docs/api-guide/schemas.md @@ -128,9 +128,11 @@ that include the Core JSON media type in their `Accept` header. This is a great zero-configuration option for when you want to get up and running really quickly. -The only other available option to `DefaultRouter` is `schema_renderers`, which -may be used to pass the set of renderer classes that can be used to render -schema output. +The other available options to `DefaultRouter` are: + +#### schema_renderers + +May be used to pass the set of renderer classes that can be used to render schema output. from rest_framework.renderers import CoreJSONRenderer from my_custom_package import APIBlueprintRenderer @@ -139,6 +141,17 @@ schema output. CoreJSONRenderer, APIBlueprintRenderer ]) +#### schema_url + +May be used to pass the root URL for the schema. This can either be used to ensure that +the schema URLs include a canonical hostname and schema, or to ensure that all the +schema URLs include a path prefix. + + router = DefaultRouter( + schema_title='Server Monitoring API', + schema_url='https://www.example.org/api/' + ) + If you want more flexibility over the schema output then you'll need to consider using `SchemaGenerator` instead. @@ -264,6 +277,7 @@ Typically you'll instantiate `SchemaGenerator` with a single argument, like so: Arguments: * `title` - The name of the API. **required** +* `url` - The root URL of the API schema. This option is not required unless the schema is included under path prefix. * `patterns` - A list of URLs to inspect when generating the schema. Defaults to the project's URL conf. * `urlconf` - A URL conf module name to use when generating the schema. Defaults to `settings.ROOT_URLCONF`. diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 94f64265aa..3143e76541 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -23,6 +23,12 @@ from django.utils import importlib # Will be removed in Django 1.9 +try: + import urlparse # Python 2.x +except ImportError: + import urllib.parse as urlparse + + def unicode_repr(instance): # Get the repr of an instance, but ensure it is a unicode string # on both python 3 (already the case) and 2 (not the case). diff --git a/rest_framework/routers.py b/rest_framework/routers.py index 9561fa4db9..099c56d6c2 100644 --- a/rest_framework/routers.py +++ b/rest_framework/routers.py @@ -278,11 +278,14 @@ class DefaultRouter(SimpleRouter): def __init__(self, *args, **kwargs): if 'schema_renderers' in kwargs: assert 'schema_title' in kwargs, 'Missing "schema_title" argument.' + if 'schema_url' in kwargs: + assert 'schema_title' in kwargs, 'Missing "schema_title" argument.' self.schema_title = kwargs.pop('schema_title', None) + self.schema_url = kwargs.pop('schema_url', None) self.schema_renderers = kwargs.pop('schema_renderers', self.default_schema_renderers) super(DefaultRouter, self).__init__(*args, **kwargs) - def get_api_root_view(self, schema_urls=None): + def get_api_root_view(self, api_urls=None): """ Return a view to use as the API root. """ @@ -294,11 +297,12 @@ def get_api_root_view(self, schema_urls=None): view_renderers = list(api_settings.DEFAULT_RENDERER_CLASSES) schema_media_types = [] - if schema_urls and self.schema_title: + if api_urls and self.schema_title: view_renderers += list(self.schema_renderers) schema_generator = SchemaGenerator( title=self.schema_title, - patterns=schema_urls + url=self.schema_url, + patterns=api_urls ) schema_media_types = [ renderer.media_type @@ -347,7 +351,7 @@ def get_urls(self): urls = super(DefaultRouter, self).get_urls() if self.include_root_view: - view = self.get_api_root_view(schema_urls=urls) + view = self.get_api_root_view(api_urls=urls) root_url = url(r'^$', view, name=self.root_view_name) urls.append(root_url) diff --git a/rest_framework/schemas.py b/rest_framework/schemas.py index ee99a1c45b..41dc82da10 100644 --- a/rest_framework/schemas.py +++ b/rest_framework/schemas.py @@ -6,7 +6,7 @@ from django.utils import six from rest_framework import exceptions, serializers -from rest_framework.compat import coreapi, uritemplate +from rest_framework.compat import coreapi, uritemplate, urlparse from rest_framework.request import clone_request from rest_framework.views import APIView @@ -57,7 +57,7 @@ class SchemaGenerator(object): 'delete': 'destroy', } - def __init__(self, title=None, patterns=None, urlconf=None): + def __init__(self, title=None, url=None, patterns=None, urlconf=None): assert coreapi, '`coreapi` must be installed for schema support.' if patterns is None and urlconf is not None: @@ -70,7 +70,11 @@ def __init__(self, title=None, patterns=None, urlconf=None): urls = import_module(settings.ROOT_URLCONF) patterns = urls.urlpatterns + if url and not url.endswith('/'): + url += '/' + self.title = title + self.url = url self.endpoints = self.get_api_endpoints(patterns) def get_schema(self, request=None): @@ -102,7 +106,7 @@ def get_schema(self, request=None): insert_into(content, key, link) # Return the schema document. - return coreapi.Document(title=self.title, content=content) + return coreapi.Document(title=self.title, content=content, url=self.url) def get_api_endpoints(self, patterns, prefix=''): """ @@ -203,7 +207,7 @@ def get_link(self, path, method, callback): encoding = None return coreapi.Link( - url=path, + url=urlparse.urljoin(self.url, path), action=method.lower(), encoding=encoding, fields=fields