Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 941a84b

Browse files
committedAug 21, 2020
initial implementation of OAS 3.0 generateschema
1 parent 930b494 commit 941a84b

20 files changed

+2209
-3
lines changed
 

‎AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Jason Housley <housleyjk@gmail.com>
1414
Jerel Unruh <mail@unruhdesigns.com>
1515
Jonathan Senecal <contact@jonathansenecal.com>
1616
Joseba Mendivil <git@jma.email>
17+
Kieran Evans <keyz182@gmail.com>
1718
Léo S. <leo@naeka.fr>
1819
Luc Cary <luc.cary@gmail.com>
1920
Matt Layman <https://www.mattlayman.com>

‎CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ any parts of the framework not mentioned in the documentation should generally b
1313
### Added
1414

1515
* Added support for serializing nested serializers as attribute json value introducing setting `JSON_API_SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE`
16+
* Add optional support for [openapi](https://www.openapis.org/) schema generation. Enable with:
17+
```
18+
pip install djangorestframework-jsonapi['openapi']
19+
```
20+
1621

1722
### Fixed
1823

‎README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ From PyPI
106106
$ # for optional package integrations
107107
$ pip install djangorestframework-jsonapi['django-filter']
108108
$ pip install djangorestframework-jsonapi['django-polymorphic']
109+
$ pip install djangorestframework-jsonapi['openapi']
109110

110111

111112
From Source

‎docs/getting-started.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ From PyPI
6565
# for optional package integrations
6666
pip install djangorestframework-jsonapi['django-filter']
6767
pip install djangorestframework-jsonapi['django-polymorphic']
68+
pip install djangorestframework-jsonapi['openapi']
6869

6970
From Source
7071

‎docs/usage.md

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Usage
32

43
The DJA package implements a custom renderer, parser, exception handler, query filter backends, and
@@ -32,6 +31,7 @@ REST_FRAMEWORK = {
3231
'rest_framework.renderers.BrowsableAPIRenderer'
3332
),
3433
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
34+
'DEFAULT_SCHEMA_CLASS': 'rest_framework_json_api.schemas.openapi.AutoSchema',
3535
'DEFAULT_FILTER_BACKENDS': (
3636
'rest_framework_json_api.filters.QueryParameterValidationFilter',
3737
'rest_framework_json_api.filters.OrderingFilter',
@@ -937,3 +937,118 @@ The `prefetch_related` case will issue 4 queries, but they will be small and fas
937937
### Relationships
938938
### Errors
939939
-->
940+
941+
## Generating an OpenAPI Specification (OAS) 3.0 schema document
942+
943+
DRF >= 3.12 has a [new OAS schema functionality](https://www.django-rest-framework.org/api-guide/schemas/) to generate an
944+
[OAS 3.0 schema](https://www.openapis.org/) as a YAML or JSON file.
945+
946+
DJA extends DRF's schema support to generate an OAS schema in the JSON:API format.
947+
948+
### AutoSchema Settings
949+
950+
In order to produce an OAS schema that properly represents the JSON:API structure
951+
you have to either add a `schema` attribute to each view class or set the `REST_FRAMEWORK['DEFAULT_SCHEMA_CLASS']`
952+
to DJA's version of AutoSchema.
953+
954+
You can also extend the OAS schema with additional static content (a feature not available in DRF at this time).
955+
956+
#### View-based
957+
958+
```python
959+
from rest_framework_json_api.schemas.openapi import AutoSchema
960+
961+
class MyViewset(ModelViewSet):
962+
schema = AutoSchema
963+
...
964+
```
965+
966+
#### Default schema class
967+
968+
```python
969+
REST_FRAMEWORK = {
970+
# ...
971+
'DEFAULT_SCHEMA_CLASS': 'rest_framework_json_api.schemas.openapi.AutoSchema',
972+
}
973+
```
974+
975+
### Adding static OAS schema content
976+
977+
You can optionally include an OAS schema document initialization by subclassing `SchemaGenerator`
978+
and setting `schema_init`.
979+
980+
Here's an example that fills out OAS `info` and `servers` objects.
981+
982+
```python
983+
# views.py
984+
985+
from rest_framework_json_api.schemas.openapi import SchemaGenerator as JSONAPISchemaGenerator
986+
987+
988+
class MySchemaGenerator(JSONAPISchemaGenerator):
989+
"""
990+
Describe my OAS schema info in detail and list the servers where it can be found
991+
"""
992+
#: fill in some of the openapi schema
993+
schema_init = {
994+
'info': {
995+
'version': '1.0',
996+
'title': 'my demo API',
997+
'description': 'A demonstration of [OAS 3.0](https://www.openapis.org)',
998+
'contact': {
999+
'name': 'my name'
1000+
},
1001+
'license': {
1002+
'name': 'BSD 2 clause',
1003+
'url': 'https://github.com/django-json-api/django-rest-framework-json-api/blob/master/LICENSE',
1004+
}
1005+
},
1006+
'servers': [
1007+
{'url': 'https://localhost/v1', 'description': 'local docker'},
1008+
{'url': 'http://localhost:8000/v1', 'description': 'local dev'},
1009+
{'url': 'https://api.example.com/v1', 'description': 'demo server'},
1010+
{'url': '{serverURL}', 'description': 'provide your server URL',
1011+
'variables': {'serverURL': {'default': 'http://localhost:8000/v1'}}}
1012+
]
1013+
}
1014+
```
1015+
1016+
### Generate a Static Schema on Command Line
1017+
1018+
See [DRF documentation for generateschema](https://www.django-rest-framework.org/api-guide/schemas/#generating-a-static-schema-with-the-generateschema-management-command)
1019+
To generate an OAS schema document, use something like:
1020+
1021+
```text
1022+
$ django-admin generateschema --settings=example.settings \
1023+
--generator_class myapp.views.MySchemaGenerator >myschema.yaml
1024+
```
1025+
1026+
You can then use any number of OAS tools such as
1027+
[swagger-ui-watcher](https://www.npmjs.com/package/swagger-ui-watcher)
1028+
to render the schema:
1029+
```text
1030+
$ swagger-ui-watcher myschema.yaml
1031+
```
1032+
1033+
Note: Swagger-ui-watcher will complain that "DELETE operations cannot have a requestBody"
1034+
but it will still work. This [error](https://github.com/OAI/OpenAPI-Specification/pull/2117)
1035+
in the OAS specification will be fixed when [OAS 3.1.0](https://www.openapis.org/blog/2020/06/18/openapi-3-1-0-rc0-its-here)
1036+
is published.
1037+
1038+
([swagger-ui](https://www.npmjs.com/package/swagger-ui) will work silently.)
1039+
1040+
### Generate a Dynamic Schema in a View
1041+
1042+
See [DRF documentation for a Dynamic Schema](https://www.django-rest-framework.org/api-guide/schemas/#generating-a-dynamic-schema-with-schemaview).
1043+
You will need to pass in your custom SchemaGenerator if you've created one.
1044+
1045+
```python
1046+
from rest_framework.schemas import get_schema_view
1047+
from views import MySchemaGenerator
1048+
1049+
urlpatterns = [
1050+
path('openapi', get_schema_view(generator_class=MySchemaGenerator), name='openapi-schema'),
1051+
...
1052+
]
1053+
```
1054+

‎example/settings/dev.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
'django.contrib.sites',
2222
'django.contrib.sessions',
2323
'django.contrib.auth',
24+
'rest_framework_json_api',
2425
'rest_framework',
2526
'polymorphic',
2627
'example',
@@ -88,6 +89,7 @@
8889
'rest_framework.renderers.BrowsableAPIRenderer',
8990
),
9091
'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
92+
'DEFAULT_SCHEMA_CLASS': 'rest_framework_json_api.schemas.openapi.AutoSchema',
9193
'DEFAULT_FILTER_BACKENDS': (
9294
'rest_framework_json_api.filters.OrderingFilter',
9395
'rest_framework_json_api.django_filters.DjangoFilterBackend',

‎example/templates/swagger-ui.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Swagger</title>
5+
<meta charset="utf-8"/>
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.23.11/swagger-ui.css" integrity="sha256-O3WBPOmqAcumrGlHJtGp6KtuKA4S9sbEu3NCSbacxZ8=" crossorigin="anonymous" />
8+
</head>
9+
<body>
10+
<div id="swagger-ui"></div>
11+
12+
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.23.11/swagger-ui-standalone-preset.js" integrity="sha256-AGfcF/HKnhqGTZNL+pNGJ+yemAzr2tuvbP69pYbn+GU=" crossorigin="anonymous"></script>
13+
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.23.11/swagger-ui-bundle.js" integrity="sha256-wmWvmMbIQjnhA5qXYJAw60JjO3/zvM2T/BMnbdBD26w=" crossorigin="anonymous"></script>
14+
<script>
15+
const ui = SwaggerUIBundle({
16+
url: "{% url schema_url %}",
17+
dom_id: '#swagger-ui',
18+
deepLinking: true,
19+
presets: [
20+
SwaggerUIBundle.presets.apis,
21+
SwaggerUIStandalonePreset
22+
],
23+
plugins: [
24+
SwaggerUIBundle.plugins.DownloadUrl
25+
],
26+
layout: "StandaloneLayout"
27+
})
28+
</script>
29+
</body>
30+
</html>

‎example/tests/snapshots/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)
Please sign in to comment.