Repository: safe-global/safe-config-service

Issue:
Cache GET /safe-apps/ endpoint
The endpoint `GET /safe-apps` returns a list of safe-apps that can be cached (eg.: 1h) due to the nature of the endpoint (frequency of updating the app list is low). Updating the list should invalidate the cache.


Discussion:

Resolving patch:
diff --git a/src/safe_apps/views.py b/src/safe_apps/views.py
--- a/src/safe_apps/views.py
+++ b/src/safe_apps/views.py
@@ -1,3 +1,5 @@
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from rest_framework.generics import ListAPIView
 
 from .models import SafeApp
@@ -7,6 +9,10 @@
 class SafeAppsListView(ListAPIView):
     serializer_class = SafeAppsResponseSerializer
 
+    @method_decorator(cache_page(60 * 10))  # Cache 10 minutes
+    def get(self, request, *args, **kwargs):
+        return super().get(self, request, *args, **kwargs)
+
     def get_queryset(self):
         queryset = SafeApp.objects.all()
 


Test patch:
diff --git a/src/safe_apps/tests/test_views.py b/src/safe_apps/tests/test_views.py
--- a/src/safe_apps/tests/test_views.py
+++ b/src/safe_apps/tests/test_views.py
@@ -1,5 +1,7 @@
 import json
 
+from django.core.cache import cache
+from django.test import override_settings
 from django.urls import reverse
 from rest_framework.test import APITestCase
 
@@ -16,6 +18,9 @@ def test_empty_set(self):
         self.assertEqual(json.loads(response.content), [])
 
 
+@override_settings(
+    CACHES={"default": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}}
+)
 class FilterSafeAppListViewTests(APITestCase):
     def test_all_safes_returned(self):
         (safe_app_1, safe_app_2, safe_app_3) = SafeAppFactory.create_batch(3)
@@ -147,6 +152,9 @@ def test_apps_returned_on_same_key_pair(self):
         self.assertEqual(json.loads(response.content), json_response)
 
 
+@override_settings(
+    CACHES={"default": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}}
+)
 class ProviderInfoTests(APITestCase):
     def test_provider_returned_in_response(self):
         provider = ProviderFactory.create()
@@ -188,3 +196,35 @@ def test_provider_not_returned_in_response(self):
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(json.loads(response.content), json_response)
+
+
+class CacheSafeAppTests(APITestCase):
+    def test_should_cache_response(self):
+        # Clear cache and insert item
+        cache.clear()
+        safe_app_1 = SafeAppFactory.create()
+
+        json_response = [
+            {
+                "url": safe_app_1.url,
+                "name": safe_app_1.name,
+                "icon_url": safe_app_1.icon_url,
+                "description": safe_app_1.description,
+                "networks": safe_app_1.networks,
+                "provider": None,
+            }
+        ]
+        url = reverse("v1:safe-apps")
+
+        response = self.client.get(path=url, data=None, format="json")
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(json.loads(response.content), json_response)
+
+        # Insert another item
+        SafeAppFactory.create()
+
+        # Response should not have changed
+        response = self.client.get(path=url, data=None, format="json")
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(json.loads(response.content), json_response)