mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 11:46:49 +00:00
fix(api): typed URLs and accurate response schemas
- Routers use path converters (use_regex_path=False): computes, instances and flavors take <int:...> ids, so non-numeric ids get 404 and drf-spectacular derives the parameter types itself. - Each method declares what it really returns: detail serializers, a shared StatusSerializer for status-only replies, no request body for actions. Instance properties used by the details serializer get return type hints. - The create-instance API drops the firmware field. Its only accepted value was "" (BIOS), which produced an empty, invalid enum, and the UEFI branch behind it was unreachable. Clients that still send it are unaffected; DRF ignores unknown fields. The schema now passes spectacular --validate --fail-on-warn; a test keeps it that way.
This commit is contained in:
parent
61208606f7
commit
3b8869c72f
10 changed files with 95 additions and 49 deletions
7
webvirtcloud/serializers.py
Normal file
7
webvirtcloud/serializers.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
|
||||
class StatusSerializer(serializers.Serializer):
|
||||
"""Response body of API actions that only report a status message."""
|
||||
|
||||
status = serializers.CharField()
|
||||
18
webvirtcloud/test_api_schema.py
Normal file
18
webvirtcloud/test_api_schema.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import os
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
|
||||
class APISchemaTestCase(TestCase):
|
||||
def test_schema_is_valid_without_warnings(self):
|
||||
call_command("spectacular", "--validate", "--fail-on-warn", "--file", os.devnull)
|
||||
|
||||
def test_non_numeric_compute_id_is_not_routed(self):
|
||||
admin = get_user_model().objects.create_superuser("schema_admin", "a@example.com", "pw")
|
||||
client = APIClient()
|
||||
client.force_login(admin)
|
||||
self.assertEqual(client.get("/api/v1/computes/abc/instances/").status_code, 404)
|
||||
self.assertEqual(client.get("/api/v1/instances/abc/").status_code, 404)
|
||||
|
|
@ -12,21 +12,21 @@ from instances.api.viewsets import FlavorViewSet, \
|
|||
CreateInstanceViewSet
|
||||
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router = routers.SimpleRouter(use_regex_path=False)
|
||||
router.register(r'computes', ComputeViewSet)
|
||||
router.register(r'migrate', MigrateViewSet, basename='instance-migrate')
|
||||
router.register(r'flavor', FlavorViewSet, basename='instance-flavor')
|
||||
router.register(r'instances', InstancesViewSet, basename='instance')
|
||||
|
||||
compute_router = routers.NestedSimpleRouter(router, r'computes', lookup='compute')
|
||||
compute_router = routers.NestedSimpleRouter(router, r'computes', lookup='compute', use_regex_path=False)
|
||||
compute_router.register(r'instances', InstanceViewSet, basename='compute-instance')
|
||||
compute_router.register(r'instances/create/(?P<arch>[^/.]+)/(?P<machine>[^/.]+)', CreateInstanceViewSet, basename='instance-create')
|
||||
compute_router.register('instances/create/<str:arch>/<str:machine>', CreateInstanceViewSet, basename='instance-create')
|
||||
compute_router.register(r'networks', NetworkViewSet, basename='compute-network')
|
||||
compute_router.register(r'interfaces', InterfaceViewSet, basename='compute-interface')
|
||||
compute_router.register(r'storages', StorageViewSet, basename='compute-storage')
|
||||
compute_router.register(r'archs', ComputeArchitecturesView, basename='compute-archs')
|
||||
|
||||
storage_router = routers.NestedSimpleRouter(compute_router, r'storages', lookup='storage')
|
||||
storage_router = routers.NestedSimpleRouter(compute_router, r'storages', lookup='storage', use_regex_path=False)
|
||||
storage_router.register(r'volumes', VolumeViewSet, basename='compute-storage-volumes')
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue