Skip to content

Commit

Permalink
refactor(Django): improve API documentation (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphodn authored Aug 5, 2024
1 parent b44a934 commit 606119a
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 10 deletions.
8 changes: 8 additions & 0 deletions config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]

APPEND_SLASH = False

ROOT_URLCONF = "config.urls"

TEMPLATES = [
Expand Down Expand Up @@ -147,6 +149,7 @@

REST_FRAMEWORK = {
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning",
"EXCEPTION_HANDLER": "open_prices.common.middleware.custom_exception_handler",
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
"ORDERING_PARAM": "order_by",
Expand All @@ -166,8 +169,13 @@
"name": " AGPL-3.0",
"url": "https://www.gnu.org/licenses/agpl-3.0.en.html",
},
"SCHEMA_PATH_PREFIX": "/api/v[0-9]",
"ENUM_NAME_OVERRIDES": {
"LocationOsmTypeEnum": "open_prices.locations.constants.OSM_TYPE_CHOICES"
},
}


# Django Q2
# https://django-q2.readthedocs.io/
# ------------------------------------------------------------------------------
Expand Down
18 changes: 18 additions & 0 deletions open_prices/api/auth/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from rest_framework import serializers


class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()


class SessionResponseSerializer(serializers.Serializer):
access_token = serializers.CharField()
token_type = serializers.CharField()


class SessionFullSerializer(serializers.Serializer):
user_id = serializers.CharField()
token = serializers.CharField()
created = serializers.CharField()
last_used = serializers.CharField()
10 changes: 10 additions & 0 deletions open_prices/api/auth/views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import time

from django.conf import settings
from drf_spectacular.utils import extend_schema
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from open_prices.api.auth.serializers import (
LoginSerializer,
SessionFullSerializer,
SessionResponseSerializer,
)
from open_prices.common import openfoodfacts as common_openfoodfacts
from open_prices.common.authentication import (
CustomAuthentication,
Expand All @@ -17,6 +23,9 @@


class LoginView(APIView):
serializer_class = LoginSerializer

@extend_schema(responses=SessionResponseSerializer)
def post(self, request: Request) -> Response:
"""
Authentication: provide username/password
Expand Down Expand Up @@ -74,6 +83,7 @@ def post(self, request: Request) -> Response:
class SessionView(APIView):
authentication_classes = [CustomAuthentication]
permission_classes = [IsAuthenticated]
serializer_class = SessionFullSerializer

def get(self, request: Request) -> Response:
session = get_request_session(request)
Expand Down
3 changes: 2 additions & 1 deletion open_prices/api/prices/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class PriceViewSet(
def get_queryset(self):
if self.request.method in ["PATCH", "DELETE"]:
# only return prices owned by the current user
return Price.objects.filter(owner=self.request.user.user_id)
if self.request.user.is_authenticated:
return Price.objects.filter(owner=self.request.user.user_id)
return self.queryset

def get_serializer_class(self):
Expand Down
6 changes: 4 additions & 2 deletions open_prices/api/proofs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ class ProofViewSet(
permission_classes = [IsAuthenticated]
# parser_classes = [FormParser, MultiPartParser]
http_method_names = ["get", "post", "patch", "delete"] # disable "put"
# queryset = Proof.objects.all()
queryset = Proof.objects.none()
serializer_class = ProofFullSerializer
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filterset_class = ProofFilter
ordering_fields = ["date", "created"]

def get_queryset(self):
# only return proofs owned by the current user
return Proof.objects.filter(owner=self.request.user.user_id)
if self.request.user.is_authenticated:
return Proof.objects.filter(owner=self.request.user.user_id)
return self.queryset

def get_serializer_class(self):
if self.request.method == "PATCH":
Expand Down
5 changes: 5 additions & 0 deletions open_prices/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from rest_framework import serializers


class StatusSerializer(serializers.Serializer):
status = serializers.CharField()
10 changes: 5 additions & 5 deletions open_prices/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

app_name = "api"

router = routers.DefaultRouter()
router = routers.DefaultRouter(trailing_slash=False)
router.register(r"v1/users", UserViewSet, basename="users")
router.register(r"v1/locations", LocationViewSet, basename="locations")
router.register(r"v1/products", ProductViewSet, basename="products")
Expand All @@ -25,15 +25,15 @@
urlpatterns = [
path("v1/auth/", include("open_prices.api.auth.urls")),
# health check
path("v1/status", StatusView.as_view(), name="status"),
path("status", StatusView.as_view(), name="status"),
# Swagger / OpenAPI documentation
path("v1/schema", SpectacularAPIView.as_view(), name="schema"),
path("schema", SpectacularAPIView.as_view(), name="schema"),
path(
"v1/docs",
"docs",
SpectacularSwaggerView.as_view(url_name="api:schema"),
name="swagger-ui",
),
path("v1/redoc", SpectacularRedocView.as_view(url_name="api:schema"), name="redoc"),
path("redoc", SpectacularRedocView.as_view(url_name="api:schema"), name="redoc"),
]

urlpatterns += router.urls
4 changes: 4 additions & 0 deletions open_prices/api/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from drf_spectacular.utils import extend_schema
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from open_prices.api.serializers import StatusSerializer


class StatusView(APIView):
@extend_schema(responses=StatusSerializer, tags=["status"])
def get(self, request: Request) -> Response:
return Response({"status": "running"})
6 changes: 4 additions & 2 deletions open_prices/prices/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import decimal

from django.core.validators import MinValueValidator, ValidationError
from django.db import models
from django.db.models import signals
Expand Down Expand Up @@ -46,7 +48,7 @@ class Price(models.Model):
price = models.DecimalField(
max_digits=10,
decimal_places=2,
validators=[MinValueValidator(0)],
validators=[MinValueValidator(decimal.Decimal(0))],
blank=True,
null=True,
)
Expand All @@ -56,7 +58,7 @@ class Price(models.Model):
price_without_discount = models.DecimalField(
max_digits=10,
decimal_places=2,
validators=[MinValueValidator(0)],
validators=[MinValueValidator(decimal.Decimal(0))],
blank=True,
null=True,
)
Expand Down

0 comments on commit 606119a

Please sign in to comment.