Skip to content

Commit

Permalink
openapi generateschema prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
n2ygk committed Jun 5, 2019
1 parent c8b9a80 commit 7b60b9a
Show file tree
Hide file tree
Showing 17 changed files with 9,366 additions and 68,609 deletions.
2 changes: 1 addition & 1 deletion docs/another1.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class InstructorViewSet(CourseBaseViewSet):
serializer_class = InstructorSerializer


class InstructorRelationshipView(AuthnAuthzMixIn, RelationshipView):
class InstructorRelationshipView(AuthnAuthzSchemaMixIn, RelationshipView):
"""
view for instructors.relationships
"""
Expand Down
8 changes: 4 additions & 4 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ index 3fbc325..57897c8 100644
+ }
+
+
+class AuthnAuthzMixIn(object):
+class AuthnAuthzSchemaMixIn(object):
+ """
+ Common Authn/Authz stuff for all View and ViewSet-derived classes:
+ - authentication_classes: in production: Oauth2 preferred; Basic and Session for testing purposes.
Expand All @@ -1303,7 +1303,7 @@ index 3fbc325..57897c8 100644
+ required_alternate_scopes = REQUIRED_SCOPES_ALTS
+
+
+class CourseBaseViewSet(AuthnAuthzMixIn, ModelViewSet):
+class CourseBaseViewSet(AuthnAuthzSchemaMixIn, ModelViewSet):
+ """
+ Base ViewSet for all our ViewSets:
+ - Adds Authn/Authz
Expand All @@ -1329,7 +1329,7 @@ index 3fbc325..57897c8 100644


-class CourseRelationshipView(RelationshipView):
+class CourseRelationshipView(AuthnAuthzMixIn, RelationshipView):
+class CourseRelationshipView(AuthnAuthzSchemaMixIn, RelationshipView):
"""
view for relationships.course
"""
Expand All @@ -1338,7 +1338,7 @@ index 3fbc325..57897c8 100644


-class CourseTermRelationshipView(RelationshipView):
+class CourseTermRelationshipView(AuthnAuthzMixIn, RelationshipView):
+class CourseTermRelationshipView(AuthnAuthzSchemaMixIn, RelationshipView):
"""
view for relationships.course_terms
"""
Expand Down
41 changes: 41 additions & 0 deletions docs/documenting-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,47 @@ and to provide developer documentation and the familiar swagger "Try it!" functi
While "waiting" on automated OAS schema generation, I've been experimenting with manually coding a schema
to get a feeling for the value of eventually having automated schema generation.

#### Automatic Schema Generation

**NEW!**

I've prototyped automatic openapi schema generation and expect to submit a PR to the DJA project to adopt it soon.
To generate a YAML schema document:
```text
./manage.py generateschema >openapi.yaml
```

If you want a JSON schema document:
```text
./manage.py generateschema --format openapi-json >openapi.json
```

I've added a few commands to `tox.ini` to generate a schema or update the docker image with it, respectively:
```
[testenv:openapi]
deps =
-rrequirements.txt
setenv =
DJANGO_SETTINGS_MODULE = training.settings
commands =
/bin/sh -c "python manage.py generateschema --format openapi-json >docs/schemas/openapi.json"
[testenv:docker]
deps =
-rrequirements.txt
whitelist_externals =
docker
setenv =
DJANGO_SETTINGS_MODULE = training.settings
commands =
/bin/sh -c "python manage.py generateschema --format openapi-json >docs/schemas/openapi.json"
/bin/cp docs/schemas/openapi.json myapp/static/openapi/myapp.json
/bin/rm -rf dist
python setup.py bdist_wheel
docker build -t myapp:latest .
docker image save -o myapp-docker.tar myapp:latest
```

#### Composing the OAS Schema with external references.

To make things DRYer, the OAS schema can be decomposed into shareable pieces that are referenced via the `$ref` tag.
Expand Down
1 change: 1 addition & 0 deletions docs/schemas/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
myapp.json
openapi.json
3 changes: 2 additions & 1 deletion myapp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
__title__ = 'myapp'
__version__ = '0.2.4'
__author__ = 'Alan Crosswell'
__license__ = 'CCbyncsa4.0'
__license__ = 'CC BY-NC-SA 4.0'
__license_url__ = 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode'
__copyright__ = '(c) 2018-2019 The Trustees of Columbia University in the City of New York'

# Version synonym
Expand Down
Empty file added myapp/management/__init__.py
Empty file.
Empty file.
14 changes: 14 additions & 0 deletions myapp/management/commands/generateschema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from rest_framework.management.commands.generateschema import \
Command as DRFCommand

from myapp.schemas.jsonapi import JSONAPISchemaGenerator

# see https://docs.djangoproject.com/en/2.2/howto/custom-management-commands/#overriding-commands
# to make this override the DRF version


class Command(DRFCommand):
help = "Generates jsonapi.org schema for project."

def get_generator_class(self):
return JSONAPISchemaGenerator
33 changes: 21 additions & 12 deletions myapp/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import uuid

from django.core import validators
from django.db import models

# TODO: Add validations


class CommonModel(models.Model):
"""
Expand All @@ -12,13 +11,13 @@ class CommonModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False,
help_text='globally unique id (UUID4)')
effective_start_date = models.DateField(default=None, blank=True, null=True,
help_text='date when this model instance becomes valid')
help_text='date when this instance becomes valid')
effective_end_date = models.DateField(default=None, blank=True, null=True,
help_text='date when this model instance becomes invalid')
help_text='date when this instance becomes invalid')
last_mod_user_name = models.CharField(default=None, null=True, max_length=80,
help_text='who last modified this instance')
last_mod_date = models.DateField(auto_now=True,
help_text='when they modified it.')
help_text='when they modified it')

class Meta:
abstract = True
Expand All @@ -29,12 +28,18 @@ class Course(CommonModel):
A course of instruction. e.g. COMSW1002 Computing in Context
"""
school_bulletin_prefix_code = models.CharField(max_length=10)
suffix_two = models.CharField(max_length=2)
subject_area_code = models.CharField(max_length=10)
course_number = models.CharField(max_length=10)
course_identifier = models.CharField(max_length=10, unique=True)
course_name = models.CharField(max_length=80)
course_description = models.TextField()
suffix_two = models.CharField(max_length=2, help_text='two-character identifier suffix')
subject_area_code = models.CharField(max_length=10, help_text='Subject')
course_number = models.CharField(max_length=10,
help_text='"Shortcut" identifier (formerly for touch-tone registration)')
course_identifier = models.CharField(max_length=9, unique=True,
help_text='Course identifier (one-character suffix)',
validators=(
validators.RegexValidator(regex='[A-Z]{4}[0-9]{4}[A-Z]'),
validators.MinLengthValidator(limit_value=9),)
)
course_name = models.CharField(max_length=80, help_text='Course official title')
course_description = models.TextField(help_text='Course description')

class Meta:
ordering = ["course_number"]
Expand All @@ -53,7 +58,11 @@ class CourseTerm(CommonModel):
A specific course term (year+semester) instance.
e.g. 20183COMSW1002
"""
term_identifier = models.CharField(max_length=14, unique=True)
term_identifier = models.CharField(max_length=14, unique=True,
validators=(
validators.RegexValidator(regex='[0-9]{4}[123][A-Z]{4}[0-9]{4}[A-Z]'),
validators.MinLengthValidator(limit_value=14),)
)
audit_permitted_code = models.PositiveIntegerField(blank=True, default=0)
exam_credit_flag = models.BooleanField(default=True)
course = models.ForeignKey('myapp.Course', related_name='course_terms', on_delete=models.CASCADE, null=True,
Expand Down
Empty file added myapp/schemas/__init__.py
Empty file.
Loading

0 comments on commit 7b60b9a

Please sign in to comment.