Repository: ResonantGeoData/ResonantGeoData

Issue:
Improve raster STAC endpoint
Currently, to retrieve the STAC Item JSON for a raster, you must know the collection ID of the raster. This isn't very user-friendly and we are more than able to add a new endpoint that enables users to request a STAC Item for a raster without knowing its  collection.

For https://github.com/ResonantGeoData/RGD-Vue/issues/82 and #653 


The following demonstrates how a user currently must do this:

https://github.com/ResonantGeoData/ResonantGeoData/blob/d69eda7c06cc42ddce74e4f69493c2b620a454d2/django-rgd-imagery/client/rgd_imagery_client/plugin.py#L105-L110

This is fine for the Python client we are shipping, but the new Vue front-end needs to do this as well and I think it'd be worthwhile to have a dedicated endpoint for this.

Thoughts, @mcovalt?


Discussion:
The STAC API only requires a unique ID per collection. Therefore both are needed in the STAC API. We have a unique ID across all collections so knowing the collection is unnecessary.

Since this is not part of the STAC API it should be documented separately from it. Perhaps this could be cleanly done with an [action](https://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing).

Resolving patch:
diff --git a/django-rgd-imagery/client/rgd_imagery_client/plugin.py b/django-rgd-imagery/client/rgd_imagery_client/plugin.py
--- a/django-rgd-imagery/client/rgd_imagery_client/plugin.py
+++ b/django-rgd-imagery/client/rgd_imagery_client/plugin.py
@@ -103,11 +103,7 @@ def get_raster(self, raster_meta_id: Union[str, int, dict], stac: bool = False)
 
         r = self.session.get(f'rgd_imagery/raster/{raster_meta_id}').json()
         if stac:
-            # Get collection ID - TODO: if this is zero, will fail - could that happen?
-            collection_id = (
-                r['parent_raster']['image_set']['images'][0]['file']['collection'] or 'default'
-            )
-            r = self.session.get(f'stac/collection/{collection_id}/items/{raster_meta_id}').json()
+            r = self.session.get(f'rgd_imagery/raster/{raster_meta_id}/stac').json()
         return r
 
     def download_raster(
diff --git a/django-rgd-imagery/rgd_imagery/rest/viewsets.py b/django-rgd-imagery/rgd_imagery/rest/viewsets.py
--- a/django-rgd-imagery/rgd_imagery/rest/viewsets.py
+++ b/django-rgd-imagery/rgd_imagery/rest/viewsets.py
@@ -5,7 +5,7 @@
 from rgd.models.mixins import Status
 from rgd.rest.base import ModelViewSet
 from rgd.rest.mixins import TaskEventViewSetMixin
-from rgd_imagery import filters, models, serializers
+from rgd_imagery import filters, models, serializers, stac
 
 
 class ProcessedImageViewSet(ModelViewSet):
@@ -47,16 +47,16 @@ class ImageSetSpatialViewSet(ModelViewSet):
     queryset = models.ImageSetSpatial.objects.all()
 
 
-class ImageViewSet(ModelViewSet):
+class ImageViewSet(ModelViewSet, TaskEventViewSetMixin):
     # TODO: consolidate 'ImageSerializer' and 'ImageMetaSerializer'
 
     def get_serializer_class(self):
-        if self.action in {'list', 'retrieve'}:
+        if self.action in {'list', 'retrieve', 'status'}:
             return serializers.ImageMetaSerializer
         return serializers.ImageSerializer
 
     def get_queryset(self):
-        if self.action in {'list', 'retrieve'}:
+        if self.action in {'list', 'retrieve', 'status'}:
             return models.ImageMeta.objects.all()
         return models.Image.objects.all()
 
@@ -76,11 +76,21 @@ class RasterViewSet(ModelViewSet, TaskEventViewSetMixin):
     filterset_class = filters.RasterMetaFilter
 
     def get_serializer_class(self):
-        if self.action in {'list', 'retrieve'}:
+        if self.action in {'list', 'retrieve', 'status'}:
             return serializers.RasterMetaSerializer
+        if self.action in {'stac'}:
+            return stac.serializers.ItemSerializer
         return serializers.RasterSerializer
 
     def get_queryset(self):
-        if self.action in {'list', 'retrieve'}:
+        if self.action in {'list', 'retrieve', 'stac', 'status'}:
             return models.RasterMeta.objects.all()
         return models.Raster.objects.all()
+
+    @swagger_auto_schema(
+        method='GET',
+        operation_summary='Fetch the STAC Item JSON for this raster.',
+    )
+    @action(detail=True)
+    def stac(self, *args, **kwargs):
+        return ModelViewSet.retrieve(self, *args, **kwargs)
diff --git a/django-rgd-imagery/rgd_imagery/stac/__init__.py b/django-rgd-imagery/rgd_imagery/stac/__init__.py
--- a/django-rgd-imagery/rgd_imagery/stac/__init__.py
+++ b/django-rgd-imagery/rgd_imagery/stac/__init__.py
@@ -0,0 +1 @@
+from . import serializers  # noqa


Test patch: