Skip to content

Commit 48a3dbb

Browse files
committed
TG-162 Add API documentation
1 parent e581e39 commit 48a3dbb

File tree

10 files changed

+120
-0
lines changed

10 files changed

+120
-0
lines changed

bootstrap/collector.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def collect(
3939
):
4040
"""Collect options and run the setup."""
4141
project_slug = clean_project_slug(project_name, project_slug)
42+
project_description = clean_project_description()
4243
service_slug = clean_service_slug(service_slug)
4344
project_dirname = clean_project_dirname(project_dirname, project_slug, service_slug)
4445
project_url_dev = validate_or_prompt_url(
@@ -72,6 +73,7 @@ def collect(
7273
"output_dir": output_dir,
7374
"project_name": project_name,
7475
"project_slug": project_slug,
76+
"project_description": project_description,
7577
"project_dirname": project_dirname,
7678
"service_dir": service_dir,
7779
"service_slug": service_slug,
@@ -119,6 +121,11 @@ def clean_project_slug(project_name, project_slug):
119121
)
120122

121123

124+
def clean_project_description(project_slug):
125+
"""Return the project description."""
126+
return click.prompt("Project description", default="")
127+
128+
122129
def clean_service_slug(service_slug):
123130
"""Return the service slug."""
124131
return slugify(

bootstrap/runner.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def run(
2626
output_dir,
2727
project_name,
2828
project_slug,
29+
project_description,
2930
project_dirname,
3031
service_dir,
3132
service_slug,
@@ -51,6 +52,7 @@ def run(
5152
output_dir,
5253
project_name,
5354
project_slug,
55+
project_description,
5456
project_dirname,
5557
service_slug,
5658
internal_service_port,
@@ -91,6 +93,7 @@ def init_service(
9193
output_dir,
9294
project_name,
9395
project_slug,
96+
project_description,
9497
project_dirname,
9598
service_slug,
9699
internal_service_port,
@@ -110,6 +113,7 @@ def init_service(
110113
"project_dirname": project_dirname,
111114
"project_name": project_name,
112115
"project_slug": project_slug,
116+
"project_description": project_description,
113117
"project_url_dev": project_url_dev,
114118
"project_url_prod": project_url_prod,
115119
"project_url_stage": project_url_stage,

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
@click.option("--output-dir", default=OUTPUT_DIR)
2121
@click.option("--project-name", prompt=True)
2222
@click.option("--project-slug", callback=slugify_option)
23+
@click.option("--project-description")
2324
@click.option("--project-dirname")
2425
@click.option("--service-slug", callback=slugify_option)
2526
@click.option("--internal-service-port", default=8000, type=int)

{{cookiecutter.project_dirname}}/.env_template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ [email protected]
1515
DJANGO_SUPERUSER_PASSWORD={{ cookiecutter.project_slug }}
1616
DJANGO_SUPERUSER_USERNAME=${USER}
1717
EMAIL_URL=console:///
18+
DJANGO_ENABLE_API_DOCS=True
1819
PYTHONBREAKPOINT=ipdb.set_trace

{{cookiecutter.project_dirname}}/docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ services:
2626
- DJANGO_SUPERUSER_PASSWORD
2727
- DJANGO_SUPERUSER_USERNAME
2828
- EMAIL_URL
29+
- ENABLE_API_DOCS
2930
- PYTHONBREAKPOINT
3031
- SERVICE_PORT
3132
ports:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# pip-compile --output-file common.txt common.in
22
-r base.in
3+
djangorestframework-camel-case~=1.3.0
4+
djangorestframework~=3.13.0
5+
drf-spectacular~=0.22.0

{{cookiecutter.project_dirname}}/terraform/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ resource "kubernetes_secret_v1" "env" {
9191
{
9292
DJANGO_SECRET_KEY = random_password.django_secret_key.result
9393
EMAIL_URL = var.email_url
94+
ENABLE_API_DOCS = var.environment_slug == "prod" ? "False" : "True"
9495
SENTRY_DSN = var.sentry_dsn
9596
},
9697
local.use_s3 ? {

{{cookiecutter.project_dirname}}/{{cookiecutter.django_settings_dirname}}/settings.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class ProjectDefault(Configuration):
4747
"django.contrib.sessions",
4848
"django.contrib.messages",
4949
"django.contrib.staticfiles",
50+
"drf_spectacular",
5051
]
5152

5253
MIDDLEWARE = [
@@ -181,6 +182,51 @@ class ProjectDefault(Configuration):
181182

182183
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
183184

185+
# API Documentation
186+
187+
ENABLE_API_DOCS = values.BooleanValue(False)
188+
189+
# Django REST Framework
190+
# https://www.django-rest-framework.org/api-guide/settings/
191+
192+
REST_FRAMEWORK: dict = {
193+
"DEFAULT_AUTHENTICATION_CLASSES": [
194+
"rest_framework.authentication.SessionAuthentication",
195+
],
196+
"DEFAULT_FILTER_BACKENDS": [
197+
"django_filters.rest_framework.DjangoFilterBackend"
198+
],
199+
"DEFAULT_PARSER_CLASSES": [
200+
"djangorestframework_camel_case.parser.CamelCaseMultiPartParser",
201+
"djangorestframework_camel_case.parser.CamelCaseJSONParser",
202+
],
203+
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
204+
"DEFAULT_RENDERER_CLASSES": [
205+
"djangorestframework_camel_case.render.CamelCaseJSONRenderer",
206+
],
207+
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
208+
}
209+
210+
# drf-spectacular
211+
# https://drf-spectacular.readthedocs.io/en/latest/
212+
213+
SPECTACULAR_SETTINGS = {
214+
"TITLE": "{{ cookiecutter.project_name }} - API documentation",
215+
"DESCRIPTION": "{{ cookiecutter.project_description }}",
216+
"VERSION": "1.0.0",
217+
"CAMELIZE_NAMES": True,
218+
"SWAGGER_UI_SETTINGS": {
219+
"deepLinking": True,
220+
"displayRequestDuration": True,
221+
"persistAuthorization": True,
222+
"syntaxHighlight.activate": True,
223+
},
224+
"POSTPROCESSING_HOOKS": [
225+
"drf_spectacular.hooks.postprocess_schema_enums",
226+
"drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields", # noqa
227+
],
228+
}
229+
184230

185231
class Local(ProjectDefault):
186232
"""The local settings."""
@@ -251,6 +297,18 @@ class Local(ProjectDefault):
251297
"verbose_names": True,
252298
}
253299

300+
# Django REST Framework
301+
# https://www.django-rest-framework.org/api-guide/settings/
302+
303+
REST_FRAMEWORK = {
304+
**ProjectDefault.REST_FRAMEWORK,
305+
"DEFAULT_RENDERER_CLASSES": [
306+
*ProjectDefault.REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"],
307+
"djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer",
308+
],
309+
}
310+
311+
254312

255313
class Testing(ProjectDefault):
256314
"""The testing settings."""

{{cookiecutter.project_dirname}}/{{cookiecutter.django_settings_dirname}}/urls.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@
2323

2424
urlpatterns = [
2525
path("admin/", admin.site.urls),
26+
path(
27+
"api/",
28+
include(
29+
(
30+
[
31+
*(
32+
[path("", include("{{ cookiecutter.project_slug }}.urls_apibrowser"))]
33+
if settings.ENABLE_API_DOCS
34+
else []
35+
),
36+
],
37+
"api",
38+
)
39+
),
40+
),
2641
]
2742

2843
if settings.DEBUG: # pragma: no cover
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""API browser URL configuration."""
2+
3+
from django.urls import include, path
4+
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
5+
6+
urlpatterns = [
7+
path(
8+
"browser/",
9+
include(
10+
(
11+
[
12+
path(
13+
"schema/",
14+
SpectacularAPIView.as_view(
15+
urlconf="{{ cookiecutter.project_slug }}.urls"
16+
),
17+
name="schema",
18+
),
19+
path(
20+
"docs/",
21+
SpectacularSwaggerView.as_view(url_name="api:browser:schema"),
22+
name="docs",
23+
),
24+
],
25+
"browser",
26+
),
27+
),
28+
)
29+
]

0 commit comments

Comments
 (0)