diff --git a/cms/djangoapps/contentstore/api/views.py b/cms/djangoapps/contentstore/api/views.py index e8d3c49ebb..aa4f20d087 100644 --- a/cms/djangoapps/contentstore/api/views.py +++ b/cms/djangoapps/contentstore/api/views.py @@ -101,6 +101,11 @@ class CourseImportView(CourseImportExportViewMixin, GenericAPIView): } """ + # TODO: ARCH-91 + # This view is excluded from Swagger doc generation because it + # does not specify a serializer class. + exclude_from_schema = True + def post(self, request, course_id): """ Kicks off an asynchronous course import and returns an ID to be used to check diff --git a/cms/envs/common.py b/cms/envs/common.py index ead2d60857..af2236b219 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -310,6 +310,9 @@ FEATURES = { # Prevent auto auth from creating superusers or modifying existing users 'RESTRICT_AUTOMATIC_AUTH': True, + + # Set this to true to make API docs available at /api-docs/. + 'ENABLE_API_DOCS': False, } ENABLE_JASMINE = False @@ -1139,6 +1142,9 @@ INSTALLED_APPS = [ # Asset management for mako templates 'pipeline_mako', + + # API Documentation + 'rest_framework_swagger', ] diff --git a/cms/urls.py b/cms/urls.py index 2ee2d58e14..44d9282a24 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -3,6 +3,7 @@ from django.conf.urls import include, url from django.conf.urls.static import static from django.contrib.admin import autodiscover as django_autodiscover from django.utils.translation import ugettext_lazy as _ +from rest_framework_swagger.views import get_swagger_view import contentstore.views from cms.djangoapps.contentstore.views.organization import OrganizationListView @@ -263,5 +264,10 @@ urlpatterns += [ url(r'^500$', handler500), ] +if settings.FEATURES.get('ENABLE_API_DOCS'): + urlpatterns += [ + url(r'^api-docs/$', get_swagger_view(title='Studio API')), + ] + from openedx.core.djangoapps.plugins import constants as plugin_constants, plugin_urls urlpatterns.extend(plugin_urls.get_patterns(plugin_constants.ProjectType.CMS)) diff --git a/common/djangoapps/entitlements/api/v1/views.py b/common/djangoapps/entitlements/api/v1/views.py index daac72e874..3af1cb69a4 100644 --- a/common/djangoapps/entitlements/api/v1/views.py +++ b/common/djangoapps/entitlements/api/v1/views.py @@ -308,6 +308,10 @@ class EntitlementEnrollmentViewSet(viewsets.GenericViewSet): - Switch Enrollment """ authentication_classes = (JwtAuthentication, SessionAuthentication,) + # TODO: ARCH-91 + # This view is excluded from Swagger doc generation because it + # does not specify a serializer class. + exclude_from_schema = True permission_classes = (permissions.IsAuthenticated,) queryset = CourseEntitlement.objects.all() diff --git a/lms/djangoapps/support/views/enrollments.py b/lms/djangoapps/support/views/enrollments.py index c5b716e79a..87e4041f2f 100644 --- a/lms/djangoapps/support/views/enrollments.py +++ b/lms/djangoapps/support/views/enrollments.py @@ -46,6 +46,10 @@ class EnrollmentSupportListView(GenericAPIView): Allows viewing and changing learner enrollments by support staff. """ + # TODO: ARCH-91 + # This view is excluded from Swagger doc generation because it + # does not specify a serializer class. + exclude_from_schema = True @method_decorator(require_support_permission) def get(self, request, username_or_email): diff --git a/lms/djangoapps/support/views/manage_user.py b/lms/djangoapps/support/views/manage_user.py index 5d08260c19..17101299ac 100644 --- a/lms/djangoapps/support/views/manage_user.py +++ b/lms/djangoapps/support/views/manage_user.py @@ -37,6 +37,10 @@ class ManageUserDetailView(GenericAPIView): Allows viewing and disabling learner accounts by support staff. """ + # TODO: ARCH-91 + # This view is excluded from Swagger doc generation because it + # does not specify a serializer class. + exclude_from_schema = True @method_decorator(require_support_permission) def get(self, request, username_or_email): diff --git a/lms/envs/common.py b/lms/envs/common.py index 4ec2eaa4ba..2725704ecc 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -396,6 +396,9 @@ FEATURES = { # Whether to send an email for failed password reset attempts or not. This is mainly useful for notifying users # that they don't have an account associated with email addresses they believe they've registered with. 'ENABLE_PASSWORD_RESET_FAILURE_EMAIL': False, + + # Set this to true to make API docs available at /api-docs/. + 'ENABLE_API_DOCS': False, } # Settings for the course reviews tool template and identification key, set either to None to disable course reviews @@ -2310,6 +2313,9 @@ INSTALLED_APPS = [ # DRF filters 'django_filters', + + # API Documentation + 'rest_framework_swagger', ] ######################### CSRF ######################################### diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py index 71063c6cef..e4da200040 100644 --- a/lms/envs/devstack.py +++ b/lms/envs/devstack.py @@ -87,6 +87,10 @@ def should_show_debug_toolbar(request): return False return True +########################### API DOCS ################################# + +FEATURES['ENABLE_API_DOCS'] = True + ########################### PIPELINE ################################# PIPELINE_ENABLED = False diff --git a/lms/urls.py b/lms/urls.py index f1aedc8198..e69c0e95f2 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -8,6 +8,7 @@ from django.conf.urls.static import static from django.contrib.admin import autodiscover as django_autodiscover from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import RedirectView +from rest_framework_swagger.views import get_swagger_view from branding import views as branding_views from config_models.views import ConfigurationModelCurrentAPIView @@ -1073,4 +1074,9 @@ if settings.BRANCH_IO_KEY: url(r'^text-me-the-app', student_views.text_me_the_app, name='text_me_the_app'), ] +if settings.FEATURES.get('ENABLE_API_DOCS'): + urlpatterns += [ + url(r'^api-docs/$', get_swagger_view(title='LMS API')), + ] + urlpatterns.extend(plugin_urls.get_patterns(plugin_constants.ProjectType.LMS)) diff --git a/requirements/edx/base.in b/requirements/edx/base.in index 08be627bcd..f2f1573d34 100644 --- a/requirements/edx/base.in +++ b/requirements/edx/base.in @@ -52,6 +52,7 @@ django-pyfs django-ratelimit django-ratelimit-backend==1.1.1 django-require +django-rest-swagger # API documentation django-sekizai django-ses==0.8.4 django-simple-history diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 66cba51f05..ede612d11e 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -61,6 +61,8 @@ celery==3.1.25 cffi==1.11.5 charade==1.0.3 # via pysrt click==6.7 # via user-util +coreapi==2.3.3 # via django-rest-swagger, openapi-codec +coreschema==0.0.4 # via coreapi cryptography==2.1.4 cssutils==1.0.2 # via pynliner ddt==0.8.0 @@ -90,6 +92,7 @@ django-pyfs==2.0 django-ratelimit-backend==1.1.1 django-ratelimit==1.1.0 django-require==1.0.11 +django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 django-simple-history==2.0 @@ -146,6 +149,8 @@ idna==2.6 ipaddr==2.1.11 ipaddress==1.0.22 isodate==0.6.0 # via python-saml +itypes==1.1.0 # via coreapi +jinja2==2.10 # via coreschema jmespath==0.9.3 # via boto3, botocore jsondiff==1.1.1 # via edx-enterprise jsonfield==2.0.2 @@ -170,6 +175,7 @@ nodeenv==1.1.1 numpy==1.6.2 oauth2==1.9.0.post1 oauthlib==2.0.1 +openapi-codec==1.3.2 # via django-rest-swagger path.py==8.2.1 pathtools==0.1.2 paver==1.3.4 @@ -211,7 +217,7 @@ sailthru-client==2.2.3 scipy==0.14.0 shapely==1.2.16 shortuuid==0.5.0 # via edx-django-oauth2-provider -simplejson==3.14.0 # via dogapi, mailsnake, sailthru-client, zendesk +simplejson==3.14.0 # via django-rest-swagger, dogapi, mailsnake, sailthru-client, zendesk six==1.11.0 slumber==0.7.1 # via edx-rest-api-client social-auth-app-django==1.2.0 @@ -221,6 +227,7 @@ sortedcontainers==0.9.2 stevedore==1.10.0 sympy==0.7.1 unicodecsv==0.14.1 +uritemplate==3.0.0 # via coreapi urllib3==1.22 # via elasticsearch user-util==0.1.3 voluptuous==0.11.1 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index df150fed26..02dfdba1fc 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -75,6 +75,8 @@ click==6.7 colorama==0.3.9 configparser==3.5.0 constantly==15.1.0 +coreapi==2.3.3 +coreschema==0.0.4 coverage==4.2 cryptography==2.1.4 cssselect==1.0.3 @@ -109,6 +111,7 @@ django-pyfs==2.0 django-ratelimit-backend==1.1.1 django-ratelimit==1.1.0 django-require==1.0.11 +django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 django-simple-history==2.0 @@ -185,6 +188,7 @@ ipaddress==1.0.22 isodate==0.6.0 isort==4.3.4 itsdangerous==0.24 +itypes==1.1.0 jinja2-pluralize==0.3.0 jinja2==2.10 jmespath==0.9.3 @@ -219,6 +223,7 @@ nose==1.3.7 numpy==1.6.2 oauth2==1.9.0.post1 oauthlib==2.0.1 +openapi-codec==1.3.2 pa11ycrawler==1.6.2 packaging==17.1 # via sphinx parsel==1.4.0 @@ -323,6 +328,7 @@ typing==3.6.4 # via sphinx unicodecsv==0.14.1 unidecode==1.0.22 unittest2==1.1.0 +uritemplate==3.0.0 urllib3==1.22 urlobject==2.4.3 user-util==0.1.3 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 5822d8c897..876d2c1781 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -72,6 +72,8 @@ click==6.7 colorama==0.3.9 # via radon configparser==3.5.0 # via flake8, pylint constantly==15.1.0 # via twisted +coreapi==2.3.3 +coreschema==0.0.4 coverage==4.2 cryptography==2.1.4 cssselect==1.0.3 @@ -105,6 +107,7 @@ django-pyfs==2.0 django-ratelimit-backend==1.1.1 django-ratelimit==1.1.0 django-require==1.0.11 +django-rest-swagger==2.2.0 django-sekizai==0.10.0 django-ses==0.8.4 django-simple-history==2.0 @@ -177,6 +180,7 @@ ipaddress==1.0.22 isodate==0.6.0 isort==4.3.4 itsdangerous==0.24 # via flask +itypes==1.1.0 jinja2-pluralize==0.3.0 jinja2==2.10 jmespath==0.9.3 @@ -211,6 +215,7 @@ nose==1.3.7 numpy==1.6.2 oauth2==1.9.0.post1 oauthlib==2.0.1 +openapi-codec==1.3.2 pa11ycrawler==1.6.2 parsel==1.4.0 # via scrapy path.py==8.2.1 @@ -306,6 +311,7 @@ twisted==16.6.0 # via pa11ycrawler, scrapy unicodecsv==0.14.1 unidecode==1.0.22 # via python-slugify unittest2==1.1.0 # via testtools +uritemplate==3.0.0 urllib3==1.22 urlobject==2.4.3 # via pa11ycrawler user-util==0.1.3