Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add drf-spectacular for openAPI docs and document the visibility APIs… #12

Open
wants to merge 1 commit into
base: feature/visibility
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions heroic_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,17 @@ def validate(self, data):
_('Must submit a valid target using either ra/dec, hour_angle/dec, altitude/azimuth, or orbital elements')
)
return validated_data


class TargetVisibilityIntervalResponseSerializer(serializers.Serializer):
telescope_id = serializers.ListField(child=serializers.ListField(
child=serializers.DateTimeField(), min_length=2, max_length=2), allow_empty=True)


class TargetVisibilityAirmassSubSerializer(serializers.Serializer):
times = serializers.ListField(child=serializers.DateTimeField())
airmasses = serializers.ListField(child=serializers.FloatField())


class TargetVisibilityAirmassResponseSerializer(serializers.Serializer):
telescope_id = TargetVisibilityAirmassSubSerializer()
66 changes: 65 additions & 1 deletion heroic_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample

from django.contrib.auth.models import User

from heroic_api.serializers import ProfileSerializer, TargetVisibilityQuerySerializer
from heroic_api.serializers import (ProfileSerializer, TargetVisibilityQuerySerializer,
TargetVisibilityIntervalResponseSerializer,
TargetVisibilityAirmassResponseSerializer)
from heroic_api.visibility import get_rise_set_intervals_by_telescope_for_target, get_airmass_by_telescope_for_target


Expand All @@ -28,6 +31,12 @@ class TargetVisibilityAPIView(APIView):
""" A API view to get visiblity intervals for targets on telescopes
Supports being called through POST with a data dict or GET with query params
"""
serializer_class = TargetVisibilityQuerySerializer
example_response = {
'telescope_id': [['2025-03-01T16:15:00Z', '2025-03-01T19:00:37.291560Z'], ['2025-03-01T16:15:00Z', '2025-03-01T19:00:37.291560Z']],
'telescope2_id': [['2025-03-01T16:15:00Z', '2025-03-01T19:00:37.291560Z']]
}

def get_visibility(self, data):
serializer = TargetVisibilityQuerySerializer(data=data)
if serializer.is_valid():
Expand All @@ -37,9 +46,31 @@ def get_visibility(self, data):
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@extend_schema(
operation_id='query visibility intervals',
parameters=[TargetVisibilityQuerySerializer],
responses={
200: OpenApiResponse(
response=TargetVisibilityIntervalResponseSerializer,
examples=[OpenApiExample(name='Success',
value=example_response
)]
)
}
)
def get(self, request):
return self.get_visibility(request.query_params)

@extend_schema(
operation_id='query visibility intervals (post)',
responses={
200: OpenApiResponse(
response=TargetVisibilityIntervalResponseSerializer,
examples=[OpenApiExample(name='Success',
value=example_response
)]
)
})
def post(self, request):
return self.get_visibility(request.data)

Expand All @@ -48,6 +79,16 @@ class TargetAirmassAPIView(APIView):
""" A API view to get airmasses for targets on telescopes at times
Supports being called through POST with a data dict or GET with query params
"""
serializer_class = TargetVisibilityQuerySerializer
example_response = {
'telescope_id': {'times': ['2025-03-01T16:15:00Z', '2025-03-01T16:25:00.00Z', '2025-03-01T16:35:00.00Z'],
'airmasses': [1.2342, 1.34543, 1.4564]
},
'telescope2_id': {'times': ['2025-03-01T16:15:00Z', '2025-03-01T16:25:00.00Z', '2025-03-01T16:35:00.00Z'],
'airmasses': [1.2342, 1.34543, 1.4564]
},
}

def get_airmass(self, data):
serializer = TargetVisibilityQuerySerializer(data=data)
if serializer.is_valid():
Expand All @@ -57,8 +98,31 @@ def get_airmass(self, data):
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@extend_schema(
operation_id='query airmass values',
parameters=[TargetVisibilityQuerySerializer],
responses={
200: OpenApiResponse(
response=TargetVisibilityAirmassResponseSerializer,
examples=[OpenApiExample(name='Success',
value=example_response
)]
)
}
)
def get(self, request):
return self.get_airmass(request.query_params)

@extend_schema(
operation_id='query airmass values (post)',
responses={
200: OpenApiResponse(
response=TargetVisibilityAirmassResponseSerializer,
examples=[OpenApiExample(name='Success',
value=example_response
)]
)
}
)
def post(self, request):
return self.get_airmass(request.data)
10 changes: 10 additions & 0 deletions heroic_base/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
'rest_framework.authtoken',
'mozilla_django_oidc',
'heroic_api',
'drf_spectacular',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -142,10 +143,19 @@
'rest_framework.authentication.SessionAuthentication',
'heroic_api.auth_backends.HeroicTokenAuthentication',
),
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 100,
}

SPECTACULAR_SETTINGS = {
'TITLE': 'HEROIC API',
'DESCRIPTION': 'API to store telescope status and instrument capabilities and query target visibility',
'VERSION': '0.1.0',
'SERVE_INCLUDE_SCHEMA': False,
# OTHER SETTINGS
}

HEROIC_FRONT_END_BASE_URL = os.getenv('HEROIC_FRONT_END_BASE_URL', 'http://127.0.0.1:8000/')

# Client ID (OIDC_RP_CLIENT_ID) and SECRET (OIDC_RP_CLIENT_SECRET)
Expand Down
6 changes: 5 additions & 1 deletion heroic_base/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
"""
from django.contrib import admin
from django.urls import path, re_path, include

from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView

urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('mozilla_django_oidc.urls')),
re_path(r'^api/', include(('heroic_api.urls', 'api'), namespace='api')), # Include heroic_api routes
# drf-spectacular OpenAPI docs
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]
Loading