Repository: wagtail/wagtail

Issue:
Use html_url in alias_of API serialisation
As per https://github.com/wagtail/wagtail/pull/7669#issuecomment-986581644


Discussion:

Resolving patch:
diff --git a/wagtail/api/v2/serializers.py b/wagtail/api/v2/serializers.py
--- a/wagtail/api/v2/serializers.py
+++ b/wagtail/api/v2/serializers.py
@@ -146,16 +146,12 @@ class PageAliasOfField(relations.RelatedField):
     Serializes the "alias_of" field on Page objects.
     """
     def get_attribute(self, instance):
-        return instance
-
-    def to_representation(self, page):
-        if page.alias_of is None:
-            return None
-        data = OrderedDict()
-        data['id'] = page.alias_of.id
-        data['full_url'] = page.alias_of.full_url
+        return instance.alias_of
 
-        return data
+    def to_representation(self, value):
+        serializer_class = get_serializer_class(value.__class__, ['id', 'type', 'detail_url', 'html_url', 'title'], meta_fields=['type', 'detail_url', 'html_url'], base=PageSerializer)
+        serializer = serializer_class(context=self.context)
+        return serializer.to_representation(value)
 
 
 class ChildRelationField(Field):


Test patch:
diff --git a/wagtail/admin/tests/api/test_pages.py b/wagtail/admin/tests/api/test_pages.py
--- a/wagtail/admin/tests/api/test_pages.py
+++ b/wagtail/admin/tests/api/test_pages.py
@@ -526,6 +526,11 @@ def test_basic(self):
         self.assertEqual(content['meta']['parent']['meta']['detail_url'], 'http://localhost/admin/api/main/pages/5/')
         self.assertEqual(content['meta']['parent']['meta']['html_url'], 'http://localhost/blog-index/')
 
+        # Check the alias_of field
+        # See test_alias_page for a test on an alias page
+        self.assertIn('alias_of', content['meta'])
+        self.assertIsNone(content['meta']['alias_of'])
+
         # Check that the custom fields are included
         self.assertIn('date', content)
         self.assertIn('body', content)
@@ -697,6 +702,32 @@ def test_meta_ancestors(self):
         self.assertEqual(content['meta']['ancestors'][1]['title'], 'Home page')
         self.assertEqual(content['meta']['ancestors'][2]['title'], 'Blog index')
 
+    def test_alias_page(self):
+        original = Page.objects.get(id=16).specific
+        alias = original.create_alias(update_slug='new-slug')
+
+        response = self.get_response(alias.id)
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response['Content-type'], 'application/json')
+
+        # Will crash if the JSON is invalid
+        content = json.loads(response.content.decode('UTF-8'))
+
+        self.assertEqual(content['meta']['type'], 'demosite.BlogEntryPage')
+        self.assertEqual(content['meta']['html_url'], 'http://localhost/blog-index/new-slug/')
+
+        # Check alias_of field
+        self.assertIn('alias_of', content['meta'])
+        self.assertIsInstance(content['meta']['alias_of'], dict)
+        self.assertEqual(set(content['meta']['alias_of'].keys()), {'id', 'meta', 'title'})
+        self.assertEqual(content['meta']['alias_of']['id'], 16)
+        self.assertIsInstance(content['meta']['alias_of']['meta'], dict)
+        self.assertEqual(set(content['meta']['alias_of']['meta'].keys()), {'type', 'detail_url', 'html_url'})
+        self.assertEqual(content['meta']['alias_of']['meta']['type'], 'demosite.BlogEntryPage')
+        self.assertEqual(content['meta']['alias_of']['meta']['detail_url'], 'http://localhost/admin/api/main/pages/16/')
+        self.assertEqual(content['meta']['alias_of']['meta']['html_url'], 'http://localhost/blog-index/blog-post/')
+
     # FIELDS
 
     def test_remove_all_meta_fields(self):
diff --git a/wagtail/api/v2/tests/test_pages.py b/wagtail/api/v2/tests/test_pages.py
--- a/wagtail/api/v2/tests/test_pages.py
+++ b/wagtail/api/v2/tests/test_pages.py
@@ -991,6 +991,11 @@ def test_basic(self):
         self.assertEqual(content['meta']['parent']['meta']['detail_url'], 'http://localhost/api/main/pages/5/')
         self.assertEqual(content['meta']['parent']['meta']['html_url'], 'http://localhost/blog-index/')
 
+        # Check the alias_of field
+        # See test_alias_page for a test on an alias page
+        self.assertIn('alias_of', content['meta'])
+        self.assertIsNone(content['meta']['alias_of'])
+
         # Check that the custom fields are included
         self.assertIn('date', content)
         self.assertIn('body', content)
@@ -1089,6 +1094,32 @@ def test_page_with_missing_page_model(self):
         response = self.get_response(16)
         self.assertEqual(response.status_code, 200)
 
+    def test_alias_page(self):
+        original = Page.objects.get(id=16).specific
+        alias = original.create_alias(update_slug='new-slug')
+
+        response = self.get_response(alias.id)
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response['Content-type'], 'application/json')
+
+        # Will crash if the JSON is invalid
+        content = json.loads(response.content.decode('UTF-8'))
+
+        self.assertEqual(content['meta']['type'], 'demosite.BlogEntryPage')
+        self.assertEqual(content['meta']['html_url'], 'http://localhost/blog-index/new-slug/')
+
+        # Check alias_of field
+        self.assertIn('alias_of', content['meta'])
+        self.assertIsInstance(content['meta']['alias_of'], dict)
+        self.assertEqual(set(content['meta']['alias_of'].keys()), {'id', 'meta', 'title'})
+        self.assertEqual(content['meta']['alias_of']['id'], 16)
+        self.assertIsInstance(content['meta']['alias_of']['meta'], dict)
+        self.assertEqual(set(content['meta']['alias_of']['meta'].keys()), {'type', 'detail_url', 'html_url'})
+        self.assertEqual(content['meta']['alias_of']['meta']['type'], 'demosite.BlogEntryPage')
+        self.assertEqual(content['meta']['alias_of']['meta']['detail_url'], 'http://localhost/api/main/pages/16/')
+        self.assertEqual(content['meta']['alias_of']['meta']['html_url'], 'http://localhost/blog-index/blog-post/')
+
     # FIELDS
 
     @override_settings(WAGTAIL_I18N_ENABLED=True)