Repository: plone/plone.restapi (language: python)

Issue:
New endpoint to expose the Site title and the current navigation root title
See https://github.com/plone/volto/issues/3531 and https://github.com/plone/volto/issues/3530


Discussion / hints:

Fix patch:
diff --git a/docs/source/endpoints/index.md b/docs/source/endpoints/index.md
index 975d6fda2f..239b6577ad 100644
--- a/docs/source/endpoints/index.md
+++ b/docs/source/endpoints/index.md
@@ -35,6 +35,7 @@ history
 linkintegrity
 locking
 navigation
+navroot
 actions
 portrait
 principals
@@ -44,6 +45,7 @@ registry
 relations
 roles
 searching
+site
 system
 tiles
 transactions
diff --git a/docs/source/endpoints/navroot.md b/docs/source/endpoints/navroot.md
new file mode 100644
index 0000000000..30fd610177
--- /dev/null
+++ b/docs/source/endpoints/navroot.md
@@ -0,0 +1,158 @@
+---
+html_meta:
+  "description": "Navigation root is a concept that provides a way to root catalog queries, searches, and breadcrumbs in Plone."
+  "property=og:description": "Navigation root is a concept that provides a way to root catalog queries, searches, and breadcrumbs in Plone."
+  "property=og:title": "Navigation Root"
+  "keywords": "Plone, plone.restapi, REST, API, site, navigation root"
+---
+
+(navigation-root-label)=
+
+# Navigation root
+
+Plone has a concept called {term}`navigation root` which provides a way to root catalog queries, searches, breadcrumbs, and so on in a given section of the site.
+This feature is useful when working with subsites or multilingual sites, because it allows the site manager to restrict searches or navigation queries to a specific location in the site.
+
+This navigation root information is different depending on the context of the request.
+For instance, in a default multilingual site when browsing the contents inside a language folder such as `www.domain.com/en`, the context is `en` and its navigation root will be `/en/`.
+In a non-multilingual site, the context is the root of the site such as `www.domain.com` and the navigation root will be `/`.
+
+To get the information about the navigation root, the REST API has a `@navroot` contextual endpoint.
+For instance, send a `GET` request to the `@navroot` endpoint at the root of the site:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_get.req
+```
+
+The response will contain the navigation root information for the site:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_get.resp
+:language: http
+```
+
+If you request the `@navroot` of a given content item in the site:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.req
+```
+
+The response will contain the navigation root information in the context of that content item:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.resp
+:language: http
+```
+
+In a multilingual site, the root of the site will work as usual:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_site_get.req
+```
+
+The response will contain the navigation root information of the root of the site:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_site_get.resp
+:language: http
+```
+
+In a multilingual site where the language folder is the navigation root, the response has the language folder information:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_lang_folder_get.req
+```
+
+The response will contain the navigation root information for the language folder:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
+:language: http
+```
+
+In a multilingual site, if the navigation root is requested for content inside a language folder:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_lang_content_get.req
+```
+
+The response has the language folder information as a navigation root:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
+:language: http
+```
+
+(navigation-root-expansion-label)=
+
+## Expansion
+
+This endpoint can be used with the {doc}`expansion` mechanism which allows getting more information about a content item in one query, avoiding unnecessary requests.
+
+If a simple `GET` request is made on the content item, a new entry will be shown on the `@components` entry with the URL of the `@navroot` endpoint.
+
+In a standard site when querying the site root:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.req
+```
+
+The response will contain information of the site root with the navigation expanded:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.resp
+:language: http
+```
+
+When querying a content item inside the root:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.req
+```
+
+The response will contain the information of that content item with its navigation root information expanded:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
+:language: http
+```
+
+In a multilingual site, it works the same.
+Use the request:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/site_get_expand_navroot.req
+```
+
+And the response will contain the navigation root information pointing to the root of the site:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/site_get_expand_navroot.resp
+:language: http
+```
+
+It will also work with language root folders that are navigation roots:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.req
+```
+
+The response will contain the navigation root information expanded:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
+:language: http
+```
+
+And also for content inside the language root folders:
+
+```{eval-rst}
+.. http:example:: curl httpie python-requests
+   :request: ../../../src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.req
+```
+
+The response will include the expanded information pointing to the language root:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
+:language: http
+```
diff --git a/docs/source/endpoints/site.md b/docs/source/endpoints/site.md
new file mode 100644
index 0000000000..40e76bf37c
--- /dev/null
+++ b/docs/source/endpoints/site.md
@@ -0,0 +1,25 @@
+---
+html_meta:
+  "description": "Site endpoint for Plone REST API"
+  "property=og:title": "Site endpoint for Plone REST API"
+  "property=og:description": "Site endpoint for Plone REST API"
+  "keywords": "Plone, plone.restapi, REST, API, site, navigation root"
+---
+
+# Site
+
+The `@site` endpoint provides general site-wide information, such as the site title, logo, and other information.
+It uses the `zope2.View` permission, which requires appropriate authorization.
+
+Send a `GET` request to the `@site` endpoint:
+
+```{eval-rst}
+..  http:example:: curl httpie python-requests
+    :request: ../../../src/plone/restapi/tests/http-examples/site_get.req
+```
+
+The response will contain the site information:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/site_get.resp
+:language: http
+```
diff --git a/docs/source/glossary.md b/docs/source/glossary.md
index 529f9e9d5a..74adaaa75b 100644
--- a/docs/source/glossary.md
+++ b/docs/source/glossary.md
@@ -53,11 +53,15 @@ Authentication Method
 
 Basic Auth
     A simple {term}`Authentication Method` referenced in the {term}`Authorization Header` that needs to be provided by the server.
-
+    
 content rule
     A content rule will automatically perform an action when a certain event, known as a {term}`trigger`, takes place.
 
 trigger
     A trigger is an event in Plone that causes the execution of defined actions.
     Example triggers include object modified, user logged in, and workflow state changed.
+
+navigation root
+    An object marked as a navigation root provides a way to root catalog queries, searches, breadcrumbs, and so on, into that object.
+
 ```
diff --git a/docs/source/index.md b/docs/source/index.md
index afeb5c9e05..1560bc7bd4 100644
--- a/docs/source/index.md
+++ b/docs/source/index.md
@@ -31,7 +31,6 @@ contributing/index
 .. include:: ../../README.rst
 ```
 
-
 ## Appendix and Glossary
 
 ```{toctree}
@@ -39,7 +38,6 @@ http-status-codes
 /glossary
 ```
 
-
 ## Index
 
 - {ref}`genindex`
diff --git a/news/1464.feature b/news/1464.feature
new file mode 100644
index 0000000000..5e52088d8b
--- /dev/null
+++ b/news/1464.feature
@@ -0,0 +1,1 @@
+Added `@site` and `@navroot` endpoints. @erral 
diff --git a/src/plone/restapi/services/configure.zcml b/src/plone/restapi/services/configure.zcml
index fa2888e292..f22f4a2071 100644
--- a/src/plone/restapi/services/configure.zcml
+++ b/src/plone/restapi/services/configure.zcml
@@ -25,6 +25,7 @@
   <include package=".history" />
   <include package=".linkintegrity" />
   <include package=".locking" />
+  <include package=".navroot" />
   <include package=".principals" />
   <include package=".querysources" />
   <include package=".querystring" />
@@ -33,6 +34,7 @@
   <include package=".relations" />
   <include package=".roles" />
   <include package=".search" />
+  <include package=".site" />
   <include package=".system" />
   <include package=".sources" />
   <include package=".transactions" />
diff --git a/src/plone/restapi/services/navroot/__init__.py b/src/plone/restapi/services/navroot/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/plone/restapi/services/navroot/configure.zcml b/src/plone/restapi/services/navroot/configure.zcml
new file mode 100644
index 0000000000..a9a8451388
--- /dev/null
+++ b/src/plone/restapi/services/navroot/configure.zcml
@@ -0,0 +1,23 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:cache="http://namespaces.zope.org/cache"
+    xmlns:plone="http://namespaces.plone.org/plone"
+    xmlns:zcml="http://namespaces.zope.org/zcml"
+    >
+
+  <plone:service
+      method="GET"
+      factory=".get.NavrootGet"
+      for="zope.interface.Interface"
+      permission="zope2.View"
+      name="@navroot"
+      />
+
+
+  <adapter
+      factory=".get.Navroot"
+      name="navroot"
+      />
+
+
+</configure>
diff --git a/src/plone/restapi/services/navroot/get.py b/src/plone/restapi/services/navroot/get.py
new file mode 100644
index 0000000000..4609a8bd18
--- /dev/null
+++ b/src/plone/restapi/services/navroot/get.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+from plone.restapi.interfaces import IExpandableElement, ISerializeToJson
+from plone.restapi.services import Service
+from zope.component import adapter
+from zope.component import getMultiAdapter
+from zope.interface import implementer
+from zope.interface import Interface
+
+
+@implementer(IExpandableElement)
+@adapter(Interface, Interface)
+class Navroot:
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def __call__(self, expand=False):
+        result = {"navroot": {"@id": f"{self.context.absolute_url()}/@navroot"}}
+        if not expand:
+            return result
+
+        portal_state = getMultiAdapter(
+            (self.context, self.request), name="plone_portal_state"
+        )
+        # We need to unset expansion here, otherwise we get infinite recursion
+        self.request.form["expand"] = ""
+
+        result["navroot"]["navroot"] = getMultiAdapter(
+            (portal_state.navigation_root(), self.request),
+            ISerializeToJson,
+        )()
+
+        return result
+
+
+class NavrootGet(Service):
+    def reply(self):
+        navroot = Navroot(self.context, self.request)
+        return navroot(expand=True)["navroot"]
diff --git a/src/plone/restapi/services/site/__init__.py b/src/plone/restapi/services/site/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/plone/restapi/services/site/configure.zcml b/src/plone/restapi/services/site/configure.zcml
new file mode 100644
index 0000000000..76bc963b44
--- /dev/null
+++ b/src/plone/restapi/services/site/configure.zcml
@@ -0,0 +1,14 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:plone="http://namespaces.plone.org/plone"
+    >
+
+  <plone:service
+      method="GET"
+      factory=".get.SiteGet"
+      for="Products.CMFPlone.interfaces.IPloneSiteRoot"
+      permission="zope2.View"
+      name="@site"
+      />
+
+</configure>
diff --git a/src/plone/restapi/services/site/get.py b/src/plone/restapi/services/site/get.py
new file mode 100644
index 0000000000..125c56621d
--- /dev/null
+++ b/src/plone/restapi/services/site/get.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+from plone.registry.interfaces import IRegistry
+from plone.restapi.interfaces import IExpandableElement
+from plone.restapi.services import Service
+from Products.CMFPlone.interfaces import IImagingSchema
+from Products.CMFPlone.interfaces import ISiteSchema
+from Products.CMFPlone.utils import getSiteLogo
+from zope.component import adapter
+from zope.component import getMultiAdapter
+from zope.component import getUtility
+from zope.interface import implementer
+from zope.interface import Interface
+
+
+@implementer(IExpandableElement)
+@adapter(Interface, Interface)
+class Site:
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def __call__(self, expand=False):
+        result = {"site": {"@id": f"{self.context.absolute_url()}/@site"}}
+        if not expand:
+            return result
+
+        portal_state = getMultiAdapter(
+            (self.context, self.request), name="plone_portal_state"
+        )
+        registry = getUtility(IRegistry)
+        site_settings = registry.forInterface(ISiteSchema, prefix="plone", check=False)
+        image_settings = registry.forInterface(
+            IImagingSchema, prefix="plone", check=False
+        )
+        result["site"].update(
+            {
+                "plone.site_title": portal_state.portal_title(),
+                "plone.site_logo": site_settings.site_logo and getSiteLogo() or None,
+                "plone.robots_txt": site_settings.robots_txt,
+                "plone.allowed_sizes": image_settings.allowed_sizes,
+            }
+        )
+
+        return result
+
+
+class SiteGet(Service):
+    def reply(self):
+        site = Site(self.context, self.request)
+        return site(expand=True)["site"]


Test patch:
diff --git a/src/plone/restapi/testing.py b/src/plone/restapi/testing.py
index 0fdaf011f9..75950efe68 100644
--- a/src/plone/restapi/testing.py
+++ b/src/plone/restapi/testing.py
@@ -30,6 +30,7 @@
 from zope.configuration import xmlconfig
 from zope.interface import implementer
 
+
 import collective.MockMailHost
 import os
 import re
@@ -205,7 +206,8 @@ def setUpPloneSite(self, portal):
 
 PLONE_RESTAPI_DX_PAM_FIXTURE = PloneRestApiDXPAMLayer()
 PLONE_RESTAPI_DX_PAM_INTEGRATION_TESTING = IntegrationTesting(
-    bases=(PLONE_RESTAPI_DX_PAM_FIXTURE,), name="PloneRestApiDXPAMLayer:Integration"
+    bases=(PLONE_RESTAPI_DX_PAM_FIXTURE,),
+    name="PloneRestApiDXPAMLayer:Integration",
 )
 PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING = FunctionalTesting(
     bases=(PLONE_RESTAPI_DX_PAM_FIXTURE, zope.WSGI_SERVER_FIXTURE),
@@ -271,7 +273,8 @@ def setUpPloneSite(self, portal):
 
 PLONE_RESTAPI_BLOCKS_FIXTURE = PloneRestApIBlocksLayer()
 PLONE_RESTAPI_BLOCKS_INTEGRATION_TESTING = IntegrationTesting(
-    bases=(PLONE_RESTAPI_BLOCKS_FIXTURE,), name="PloneRestApIBlocksLayer:Integration"
+    bases=(PLONE_RESTAPI_BLOCKS_FIXTURE,),
+    name="PloneRestApIBlocksLayer:Integration",
 )
 PLONE_RESTAPI_BLOCKS_FUNCTIONAL_TESTING = FunctionalTesting(
     bases=(PLONE_RESTAPI_BLOCKS_FIXTURE, zope.WSGI_SERVER_FIXTURE),
diff --git a/src/plone/restapi/tests/http-examples/collection.resp b/src/plone/restapi/tests/http-examples/collection.resp
index 45a5fe15d8..740fc4bc7d 100644
--- a/src/plone/restapi/tests/http-examples/collection.resp
+++ b/src/plone/restapi/tests/http-examples/collection.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/collection/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/collection/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/collection/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/collection_fullobjects.resp b/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
index adb6bba795..b6c5da9d17 100644
--- a/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
+++ b/src/plone/restapi/tests/http-examples/collection_fullobjects.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/collection/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/collection/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/collection/@types"
         },
@@ -77,6 +80,9 @@ Content-Type: application/json
                 "navigation": {
                     "@id": "http://localhost:55001/plone/front-page/@navigation"
                 },
+                "navroot": {
+                    "@id": "http://localhost:55001/plone/front-page/@navroot"
+                },
                 "types": {
                     "@id": "http://localhost:55001/plone/front-page/@types"
                 },
@@ -156,6 +162,9 @@ Content-Type: application/json
                 "navigation": {
                     "@id": "http://localhost:55001/plone/doc1/@navigation"
                 },
+                "navroot": {
+                    "@id": "http://localhost:55001/plone/doc1/@navroot"
+                },
                 "types": {
                     "@id": "http://localhost:55001/plone/doc1/@types"
                 },
@@ -237,6 +246,9 @@ Content-Type: application/json
                 "navigation": {
                     "@id": "http://localhost:55001/plone/doc2/@navigation"
                 },
+                "navroot": {
+                    "@id": "http://localhost:55001/plone/doc2/@navroot"
+                },
                 "types": {
                     "@id": "http://localhost:55001/plone/doc2/@types"
                 },
diff --git a/src/plone/restapi/tests/http-examples/content_get.resp b/src/plone/restapi/tests/http-examples/content_get.resp
index 1581c04f2f..c2ce316883 100644
--- a/src/plone/restapi/tests/http-examples/content_get.resp
+++ b/src/plone/restapi/tests/http-examples/content_get.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/folder/my-document/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/folder/my-document/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/folder/my-document/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/content_get_folder.resp b/src/plone/restapi/tests/http-examples/content_get_folder.resp
index 159a88f459..a1ab52dc22 100644
--- a/src/plone/restapi/tests/http-examples/content_get_folder.resp
+++ b/src/plone/restapi/tests/http-examples/content_get_folder.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/folder/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/folder/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/folder/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/content_patch_representation.resp b/src/plone/restapi/tests/http-examples/content_patch_representation.resp
index ceccd7c396..9f26814f27 100644
--- a/src/plone/restapi/tests/http-examples/content_patch_representation.resp
+++ b/src/plone/restapi/tests/http-examples/content_patch_representation.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/folder/my-document/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/folder/my-document/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/folder/my-document/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/content_post.resp b/src/plone/restapi/tests/http-examples/content_post.resp
index f23cb1a78c..d9930ffcfa 100644
--- a/src/plone/restapi/tests/http-examples/content_post.resp
+++ b/src/plone/restapi/tests/http-examples/content_post.resp
@@ -19,6 +19,9 @@ Location: http://localhost:55001/plone/folder/my-document
         "navigation": {
             "@id": "http://localhost:55001/plone/folder/my-document/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/folder/my-document/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/folder/my-document/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/document.resp b/src/plone/restapi/tests/http-examples/document.resp
index ea83793343..46a8f7d793 100644
--- a/src/plone/restapi/tests/http-examples/document.resp
+++ b/src/plone/restapi/tests/http-examples/document.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/front-page/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/front-page/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/front-page/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/event.resp b/src/plone/restapi/tests/http-examples/event.resp
index 02bccc41ec..d66635ce26 100644
--- a/src/plone/restapi/tests/http-examples/event.resp
+++ b/src/plone/restapi/tests/http-examples/event.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/event/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/event/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/event/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/expansion.resp b/src/plone/restapi/tests/http-examples/expansion.resp
index ea83793343..46a8f7d793 100644
--- a/src/plone/restapi/tests/http-examples/expansion.resp
+++ b/src/plone/restapi/tests/http-examples/expansion.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/front-page/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/front-page/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/front-page/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/expansion_expanded.resp b/src/plone/restapi/tests/http-examples/expansion_expanded.resp
index e6dc096cdb..c12bb51211 100644
--- a/src/plone/restapi/tests/http-examples/expansion_expanded.resp
+++ b/src/plone/restapi/tests/http-examples/expansion_expanded.resp
@@ -25,6 +25,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/front-page/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/front-page/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/front-page/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp b/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
index 7682f36f03..e504dae3b0 100644
--- a/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
+++ b/src/plone/restapi/tests/http-examples/expansion_expanded_full.resp
@@ -159,6 +159,9 @@ Content-Type: application/json
                 }
             ]
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/front-page/@navroot"
+        },
         "types": [
             {
                 "@id": "http://localhost:55001/plone/@types/Collection",
diff --git a/src/plone/restapi/tests/http-examples/file.resp b/src/plone/restapi/tests/http-examples/file.resp
index 2884e386c8..efc75551cb 100644
--- a/src/plone/restapi/tests/http-examples/file.resp
+++ b/src/plone/restapi/tests/http-examples/file.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/file/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/file/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/file/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/folder.resp b/src/plone/restapi/tests/http-examples/folder.resp
index 3f645548df..b2aac1e5da 100644
--- a/src/plone/restapi/tests/http-examples/folder.resp
+++ b/src/plone/restapi/tests/http-examples/folder.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/folder/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/folder/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/folder/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/image.resp b/src/plone/restapi/tests/http-examples/image.resp
index e6223e7052..4dfb1ad451 100644
--- a/src/plone/restapi/tests/http-examples/image.resp
+++ b/src/plone/restapi/tests/http-examples/image.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/image/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/image/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/image/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/jwt_logged_in.resp b/src/plone/restapi/tests/http-examples/jwt_logged_in.resp
index 13b18a2921..51b29477ff 100644
--- a/src/plone/restapi/tests/http-examples/jwt_logged_in.resp
+++ b/src/plone/restapi/tests/http-examples/jwt_logged_in.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/link.resp b/src/plone/restapi/tests/http-examples/link.resp
index afc3ee3258..7f6165b777 100644
--- a/src/plone/restapi/tests/http-examples/link.resp
+++ b/src/plone/restapi/tests/http-examples/link.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/link/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/link/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/link/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_content_get.req b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.req
new file mode 100644
index 0000000000..a16879755c
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.req
@@ -0,0 +1,3 @@
+GET /plone/en/test-document/@navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
new file mode 100644
index 0000000000..a6ff5e542e
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_content_get.resp
@@ -0,0 +1,101 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/en/test-document/@navroot",
+    "navroot": {
+        "@components": {
+            "actions": {
+                "@id": "http://localhost:55001/plone/en/@actions"
+            },
+            "aliases": {
+                "@id": "http://localhost:55001/plone/en/@aliases"
+            },
+            "breadcrumbs": {
+                "@id": "http://localhost:55001/plone/en/@breadcrumbs"
+            },
+            "contextnavigation": {
+                "@id": "http://localhost:55001/plone/en/@contextnavigation"
+            },
+            "navigation": {
+                "@id": "http://localhost:55001/plone/en/@navigation"
+            },
+            "navroot": {
+                "@id": "http://localhost:55001/plone/en/@navroot"
+            },
+            "translations": {
+                "@id": "http://localhost:55001/plone/en/@translations"
+            },
+            "types": {
+                "@id": "http://localhost:55001/plone/en/@types"
+            },
+            "workflow": {
+                "@id": "http://localhost:55001/plone/en/@workflow"
+            }
+        },
+        "@id": "http://localhost:55001/plone/en",
+        "@type": "LRF",
+        "UID": "00000000000000000000000000000001",
+        "allow_discussion": false,
+        "contributors": [],
+        "created": "1995-07-31T13:45:00",
+        "creators": [
+            "admin"
+        ],
+        "description": "",
+        "effective": null,
+        "exclude_from_nav": true,
+        "expires": null,
+        "id": "en",
+        "is_folderish": true,
+        "items": [
+            {
+                "@id": "http://localhost:55001/plone/en/assets",
+                "@type": "LIF",
+                "description": "",
+                "review_state": "published",
+                "title": "Assets",
+                "type_title": "Language Independent Folder"
+            },
+            {
+                "@id": "http://localhost:55001/plone/en/test-document",
+                "@type": "Document",
+                "description": "",
+                "review_state": "private",
+                "title": "Test document",
+                "type_title": "Page"
+            }
+        ],
+        "items_total": 2,
+        "language": {
+            "title": "English",
+            "token": "en"
+        },
+        "layout": "folder_listing",
+        "lock": {},
+        "modified": "1995-07-31T17:30:00",
+        "next_item": {
+            "@id": "http://localhost:55001/plone/de",
+            "@type": "LRF",
+            "description": "",
+            "title": "Deutsch",
+            "type_title": "Language Root Folder"
+        },
+        "parent": {
+            "@id": "http://localhost:55001/plone",
+            "@type": "Plone Site",
+            "description": "",
+            "title": "Plone site",
+            "type_title": "Plone Site"
+        },
+        "previous_item": {},
+        "review_state": "published",
+        "rights": "",
+        "subjects": [],
+        "title": "English",
+        "type_title": "Language Root Folder",
+        "version": "current",
+        "working_copy": null,
+        "working_copy_of": null
+    }
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.req b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.req
new file mode 100644
index 0000000000..5bbb15c017
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.req
@@ -0,0 +1,3 @@
+GET /plone/en/@navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
new file mode 100644
index 0000000000..0b506e7ac3
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_lang_folder_get.resp
@@ -0,0 +1,101 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/en/@navroot",
+    "navroot": {
+        "@components": {
+            "actions": {
+                "@id": "http://localhost:55001/plone/en/@actions"
+            },
+            "aliases": {
+                "@id": "http://localhost:55001/plone/en/@aliases"
+            },
+            "breadcrumbs": {
+                "@id": "http://localhost:55001/plone/en/@breadcrumbs"
+            },
+            "contextnavigation": {
+                "@id": "http://localhost:55001/plone/en/@contextnavigation"
+            },
+            "navigation": {
+                "@id": "http://localhost:55001/plone/en/@navigation"
+            },
+            "navroot": {
+                "@id": "http://localhost:55001/plone/en/@navroot"
+            },
+            "translations": {
+                "@id": "http://localhost:55001/plone/en/@translations"
+            },
+            "types": {
+                "@id": "http://localhost:55001/plone/en/@types"
+            },
+            "workflow": {
+                "@id": "http://localhost:55001/plone/en/@workflow"
+            }
+        },
+        "@id": "http://localhost:55001/plone/en",
+        "@type": "LRF",
+        "UID": "00000000000000000000000000000001",
+        "allow_discussion": false,
+        "contributors": [],
+        "created": "1995-07-31T13:45:00",
+        "creators": [
+            "admin"
+        ],
+        "description": "",
+        "effective": null,
+        "exclude_from_nav": true,
+        "expires": null,
+        "id": "en",
+        "is_folderish": true,
+        "items": [
+            {
+                "@id": "http://localhost:55001/plone/en/assets",
+                "@type": "LIF",
+                "description": "",
+                "review_state": "published",
+                "title": "Assets",
+                "type_title": "Language Independent Folder"
+            },
+            {
+                "@id": "http://localhost:55001/plone/en/test-document",
+                "@type": "Document",
+                "description": "",
+                "review_state": "private",
+                "title": "Test document",
+                "type_title": "Page"
+            }
+        ],
+        "items_total": 2,
+        "language": {
+            "title": "English",
+            "token": "en"
+        },
+        "layout": "folder_listing",
+        "lock": {},
+        "modified": "1995-07-31T17:30:00",
+        "next_item": {
+            "@id": "http://localhost:55001/plone/de",
+            "@type": "LRF",
+            "description": "",
+            "title": "Deutsch",
+            "type_title": "Language Root Folder"
+        },
+        "parent": {
+            "@id": "http://localhost:55001/plone",
+            "@type": "Plone Site",
+            "description": "",
+            "title": "Plone site",
+            "type_title": "Plone Site"
+        },
+        "previous_item": {},
+        "review_state": "published",
+        "rights": "",
+        "subjects": [],
+        "title": "English",
+        "type_title": "Language Root Folder",
+        "version": "current",
+        "working_copy": null,
+        "working_copy_of": null
+    }
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_site_get.req b/src/plone/restapi/tests/http-examples/navroot_site_get.req
new file mode 100644
index 0000000000..cc9c5ca1e8
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_site_get.req
@@ -0,0 +1,3 @@
+GET /plone/@navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_site_get.resp b/src/plone/restapi/tests/http-examples/navroot_site_get.resp
new file mode 100644
index 0000000000..8773250024
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_site_get.resp
@@ -0,0 +1,100 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/@navroot",
+    "navroot": {
+        "@components": {
+            "actions": {
+                "@id": "http://localhost:55001/plone/@actions"
+            },
+            "aliases": {
+                "@id": "http://localhost:55001/plone/@aliases"
+            },
+            "breadcrumbs": {
+                "@id": "http://localhost:55001/plone/@breadcrumbs"
+            },
+            "contextnavigation": {
+                "@id": "http://localhost:55001/plone/@contextnavigation"
+            },
+            "navigation": {
+                "@id": "http://localhost:55001/plone/@navigation"
+            },
+            "navroot": {
+                "@id": "http://localhost:55001/plone/@navroot"
+            },
+            "types": {
+                "@id": "http://localhost:55001/plone/@types"
+            },
+            "workflow": {
+                "@id": "http://localhost:55001/plone/@workflow"
+            }
+        },
+        "@id": "http://localhost:55001/plone",
+        "@type": "Plone Site",
+        "UID": "55c25ebc220d400393574f37d648727c",
+        "allow_discussion": null,
+        "contributors": [],
+        "creators": [
+            "admin"
+        ],
+        "description": "",
+        "effective": null,
+        "exclude_from_nav": false,
+        "expires": null,
+        "id": "plone",
+        "is_folderish": true,
+        "items": [
+            {
+                "@id": "http://localhost:55001/plone/en",
+                "@type": "LRF",
+                "description": "",
+                "review_state": "published",
+                "title": "English",
+                "type_title": "Language Root Folder"
+            },
+            {
+                "@id": "http://localhost:55001/plone/de",
+                "@type": "LRF",
+                "description": "",
+                "review_state": "published",
+                "title": "Deutsch",
+                "type_title": "Language Root Folder"
+            },
+            {
+                "@id": "http://localhost:55001/plone/es",
+                "@type": "LRF",
+                "description": "",
+                "review_state": "published",
+                "title": "Espa\u00f1ol",
+                "type_title": "Language Root Folder"
+            },
+            {
+                "@id": "http://localhost:55001/plone/fr",
+                "@type": "LRF",
+                "description": "",
+                "review_state": null,
+                "title": "Fran\u00e7ais",
+                "type_title": "Language Root Folder"
+            }
+        ],
+        "items_total": 4,
+        "language": {
+            "title": "English",
+            "token": "en"
+        },
+        "lock": {
+            "locked": false,
+            "stealable": true
+        },
+        "parent": {},
+        "relatedItems": [],
+        "review_state": null,
+        "rights": "",
+        "subjects": [],
+        "table_of_contents": null,
+        "text": null,
+        "title": "Plone site",
+        "type_title": "Plone Site"
+    }
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.req b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.req
new file mode 100644
index 0000000000..4611396f72
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.req
@@ -0,0 +1,3 @@
+GET /plone/front-page/@navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.resp b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.resp
new file mode 100644
index 0000000000..0c374d5389
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get.resp
@@ -0,0 +1,76 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/front-page/@navroot",
+    "navroot": {
+        "@components": {
+            "actions": {
+                "@id": "http://localhost:55001/plone/@actions"
+            },
+            "aliases": {
+                "@id": "http://localhost:55001/plone/@aliases"
+            },
+            "breadcrumbs": {
+                "@id": "http://localhost:55001/plone/@breadcrumbs"
+            },
+            "contextnavigation": {
+                "@id": "http://localhost:55001/plone/@contextnavigation"
+            },
+            "navigation": {
+                "@id": "http://localhost:55001/plone/@navigation"
+            },
+            "navroot": {
+                "@id": "http://localhost:55001/plone/@navroot"
+            },
+            "types": {
+                "@id": "http://localhost:55001/plone/@types"
+            },
+            "workflow": {
+                "@id": "http://localhost:55001/plone/@workflow"
+            }
+        },
+        "@id": "http://localhost:55001/plone",
+        "@type": "Plone Site",
+        "UID": "55c25ebc220d400393574f37d648727c",
+        "allow_discussion": null,
+        "contributors": [],
+        "creators": [
+            "admin"
+        ],
+        "description": "",
+        "effective": null,
+        "exclude_from_nav": false,
+        "expires": null,
+        "id": "plone",
+        "is_folderish": true,
+        "items": [
+            {
+                "@id": "http://localhost:55001/plone/front-page",
+                "@type": "Document",
+                "description": "Congratulations! You have successfully installed Plone.",
+                "review_state": "private",
+                "title": "Welcome to Plone",
+                "type_title": "Page"
+            }
+        ],
+        "items_total": 1,
+        "language": {
+            "title": "English",
+            "token": "en"
+        },
+        "lock": {
+            "locked": false,
+            "stealable": true
+        },
+        "parent": {},
+        "relatedItems": [],
+        "review_state": null,
+        "rights": "",
+        "subjects": [],
+        "table_of_contents": null,
+        "text": null,
+        "title": "Plone site",
+        "type_title": "Plone Site"
+    }
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.req b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.req
new file mode 100644
index 0000000000..20266313b2
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.req
@@ -0,0 +1,3 @@
+GET /plone/front-page?expand=navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
new file mode 100644
index 0000000000..abfbe7e93f
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_content_get_expansion.resp
@@ -0,0 +1,149 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@components": {
+        "actions": {
+            "@id": "http://localhost:55001/plone/front-page/@actions"
+        },
+        "aliases": {
+            "@id": "http://localhost:55001/plone/front-page/@aliases"
+        },
+        "breadcrumbs": {
+            "@id": "http://localhost:55001/plone/front-page/@breadcrumbs"
+        },
+        "contextnavigation": {
+            "@id": "http://localhost:55001/plone/front-page/@contextnavigation"
+        },
+        "navigation": {
+            "@id": "http://localhost:55001/plone/front-page/@navigation"
+        },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/front-page/@navroot",
+            "navroot": {
+                "@components": {
+                    "actions": {
+                        "@id": "http://localhost:55001/plone/@actions"
+                    },
+                    "aliases": {
+                        "@id": "http://localhost:55001/plone/@aliases"
+                    },
+                    "breadcrumbs": {
+                        "@id": "http://localhost:55001/plone/@breadcrumbs"
+                    },
+                    "contextnavigation": {
+                        "@id": "http://localhost:55001/plone/@contextnavigation"
+                    },
+                    "navigation": {
+                        "@id": "http://localhost:55001/plone/@navigation"
+                    },
+                    "navroot": {
+                        "@id": "http://localhost:55001/plone/@navroot"
+                    },
+                    "types": {
+                        "@id": "http://localhost:55001/plone/@types"
+                    },
+                    "workflow": {
+                        "@id": "http://localhost:55001/plone/@workflow"
+                    }
+                },
+                "@id": "http://localhost:55001/plone",
+                "@type": "Plone Site",
+                "UID": "55c25ebc220d400393574f37d648727c",
+                "allow_discussion": null,
+                "contributors": [],
+                "creators": [
+                    "admin"
+                ],
+                "description": "",
+                "effective": null,
+                "exclude_from_nav": false,
+                "expires": null,
+                "id": "plone",
+                "is_folderish": true,
+                "items": [
+                    {
+                        "@id": "http://localhost:55001/plone/front-page",
+                        "@type": "Document",
+                        "description": "Congratulations! You have successfully installed Plone.",
+                        "review_state": "private",
+                        "title": "Welcome to Plone",
+                        "type_title": "Page"
+                    }
+                ],
+                "items_total": 1,
+                "language": {
+                    "title": "English",
+                    "token": "en"
+                },
+                "lock": {
+                    "locked": false,
+                    "stealable": true
+                },
+                "parent": {},
+                "relatedItems": [],
+                "review_state": null,
+                "rights": "",
+                "subjects": [],
+                "table_of_contents": null,
+                "text": null,
+                "title": "Plone site",
+                "type_title": "Plone Site"
+            }
+        },
+        "types": {
+            "@id": "http://localhost:55001/plone/front-page/@types"
+        },
+        "workflow": {
+            "@id": "http://localhost:55001/plone/front-page/@workflow"
+        }
+    },
+    "@id": "http://localhost:55001/plone/front-page",
+    "@type": "Document",
+    "UID": "SomeUUID000000000000000000000001",
+    "allow_discussion": false,
+    "changeNote": "",
+    "contributors": [],
+    "created": "1995-07-31T13:45:00",
+    "creators": [
+        "test_user_1_"
+    ],
+    "description": "Congratulations! You have successfully installed Plone.",
+    "effective": null,
+    "exclude_from_nav": false,
+    "expires": null,
+    "id": "front-page",
+    "is_folderish": false,
+    "language": "",
+    "layout": "document_view",
+    "lock": {
+        "locked": false,
+        "stealable": true
+    },
+    "modified": "1995-07-31T17:30:00",
+    "next_item": {},
+    "parent": {
+        "@id": "http://localhost:55001/plone",
+        "@type": "Plone Site",
+        "description": "",
+        "title": "Plone site",
+        "type_title": "Plone Site"
+    },
+    "previous_item": {},
+    "relatedItems": [],
+    "review_state": "private",
+    "rights": "",
+    "subjects": [],
+    "table_of_contents": null,
+    "text": {
+        "content-type": "text/plain",
+        "data": "<p>If you&#x27;re seeing this instead of the web site you were expecting, the owner of this web site has just installed Plone. Do not contact the Plone Team or the Plone mailing lists about this.</p>",
+        "encoding": "utf-8"
+    },
+    "title": "Welcome to Plone",
+    "type_title": "Page",
+    "version": "current",
+    "versioning_enabled": true,
+    "working_copy": null,
+    "working_copy_of": null
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_get.req b/src/plone/restapi/tests/http-examples/navroot_standard_site_get.req
new file mode 100644
index 0000000000..cc9c5ca1e8
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_get.req
@@ -0,0 +1,3 @@
+GET /plone/@navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_get.resp b/src/plone/restapi/tests/http-examples/navroot_standard_site_get.resp
new file mode 100644
index 0000000000..532ec7d6ca
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_get.resp
@@ -0,0 +1,76 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/@navroot",
+    "navroot": {
+        "@components": {
+            "actions": {
+                "@id": "http://localhost:55001/plone/@actions"
+            },
+            "aliases": {
+                "@id": "http://localhost:55001/plone/@aliases"
+            },
+            "breadcrumbs": {
+                "@id": "http://localhost:55001/plone/@breadcrumbs"
+            },
+            "contextnavigation": {
+                "@id": "http://localhost:55001/plone/@contextnavigation"
+            },
+            "navigation": {
+                "@id": "http://localhost:55001/plone/@navigation"
+            },
+            "navroot": {
+                "@id": "http://localhost:55001/plone/@navroot"
+            },
+            "types": {
+                "@id": "http://localhost:55001/plone/@types"
+            },
+            "workflow": {
+                "@id": "http://localhost:55001/plone/@workflow"
+            }
+        },
+        "@id": "http://localhost:55001/plone",
+        "@type": "Plone Site",
+        "UID": "55c25ebc220d400393574f37d648727c",
+        "allow_discussion": null,
+        "contributors": [],
+        "creators": [
+            "admin"
+        ],
+        "description": "",
+        "effective": null,
+        "exclude_from_nav": false,
+        "expires": null,
+        "id": "plone",
+        "is_folderish": true,
+        "items": [
+            {
+                "@id": "http://localhost:55001/plone/front-page",
+                "@type": "Document",
+                "description": "Congratulations! You have successfully installed Plone.",
+                "review_state": "private",
+                "title": "Welcome to Plone",
+                "type_title": "Page"
+            }
+        ],
+        "items_total": 1,
+        "language": {
+            "title": "English",
+            "token": "en"
+        },
+        "lock": {
+            "locked": false,
+            "stealable": true
+        },
+        "parent": {},
+        "relatedItems": [],
+        "review_state": null,
+        "rights": "",
+        "subjects": [],
+        "table_of_contents": null,
+        "text": null,
+        "title": "Plone site",
+        "type_title": "Plone Site"
+    }
+}
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.req b/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.req
new file mode 100644
index 0000000000..36c802e247
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.req
@@ -0,0 +1,3 @@
+GET /plone/?expand=navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.resp b/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.resp
new file mode 100644
index 0000000000..0a33c7475c
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/navroot_standard_site_get_expansion.resp
@@ -0,0 +1,143 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@components": {
+        "actions": {
+            "@id": "http://localhost:55001/plone/@actions"
+        },
+        "aliases": {
+            "@id": "http://localhost:55001/plone/@aliases"
+        },
+        "breadcrumbs": {
+            "@id": "http://localhost:55001/plone/@breadcrumbs"
+        },
+        "contextnavigation": {
+            "@id": "http://localhost:55001/plone/@contextnavigation"
+        },
+        "navigation": {
+            "@id": "http://localhost:55001/plone/@navigation"
+        },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/@navroot",
+            "navroot": {
+                "@components": {
+                    "actions": {
+                        "@id": "http://localhost:55001/plone/@actions"
+                    },
+                    "aliases": {
+                        "@id": "http://localhost:55001/plone/@aliases"
+                    },
+                    "breadcrumbs": {
+                        "@id": "http://localhost:55001/plone/@breadcrumbs"
+                    },
+                    "contextnavigation": {
+                        "@id": "http://localhost:55001/plone/@contextnavigation"
+                    },
+                    "navigation": {
+                        "@id": "http://localhost:55001/plone/@navigation"
+                    },
+                    "navroot": {
+                        "@id": "http://localhost:55001/plone/@navroot"
+                    },
+                    "types": {
+                        "@id": "http://localhost:55001/plone/@types"
+                    },
+                    "workflow": {
+                        "@id": "http://localhost:55001/plone/@workflow"
+                    }
+                },
+                "@id": "http://localhost:55001/plone",
+                "@type": "Plone Site",
+                "UID": "55c25ebc220d400393574f37d648727c",
+                "allow_discussion": null,
+                "contributors": [],
+                "creators": [
+                    "admin"
+                ],
+                "description": "",
+                "effective": null,
+                "exclude_from_nav": false,
+                "expires": null,
+                "id": "plone",
+                "is_folderish": true,
+                "items": [
+                    {
+                        "@id": "http://localhost:55001/plone/front-page",
+                        "@type": "Document",
+                        "description": "Congratulations! You have successfully installed Plone.",
+                        "review_state": "private",
+                        "title": "Welcome to Plone",
+                        "type_title": "Page"
+                    }
+                ],
+                "items_total": 1,
+                "language": {
+                    "title": "English",
+                    "token": "en"
+                },
+                "lock": {
+                    "locked": false,
+                    "stealable": true
+                },
+                "parent": {},
+                "relatedItems": [],
+                "review_state": null,
+                "rights": "",
+                "subjects": [],
+                "table_of_contents": null,
+                "text": null,
+                "title": "Plone site",
+                "type_title": "Plone Site"
+            }
+        },
+        "types": {
+            "@id": "http://localhost:55001/plone/@types"
+        },
+        "workflow": {
+            "@id": "http://localhost:55001/plone/@workflow"
+        }
+    },
+    "@id": "http://localhost:55001/plone",
+    "@type": "Plone Site",
+    "UID": "55c25ebc220d400393574f37d648727c",
+    "allow_discussion": null,
+    "contributors": [],
+    "creators": [
+        "admin"
+    ],
+    "description": "",
+    "effective": null,
+    "exclude_from_nav": false,
+    "expires": null,
+    "id": "plone",
+    "is_folderish": true,
+    "items": [
+        {
+            "@id": "http://localhost:55001/plone/front-page",
+            "@type": "Document",
+            "description": "Congratulations! You have successfully installed Plone.",
+            "review_state": "private",
+            "title": "Welcome to Plone",
+            "type_title": "Page"
+        }
+    ],
+    "items_total": 1,
+    "language": {
+        "title": "English",
+        "token": "en"
+    },
+    "lock": {
+        "locked": false,
+        "stealable": true
+    },
+    "parent": {},
+    "relatedItems": [],
+    "review_state": null,
+    "rights": "",
+    "subjects": [],
+    "table_of_contents": null,
+    "text": null,
+    "title": "Plone site",
+    "type_title": "Plone Site"
+}
diff --git a/src/plone/restapi/tests/http-examples/newsitem.resp b/src/plone/restapi/tests/http-examples/newsitem.resp
index 7f66055dc0..0618088231 100644
--- a/src/plone/restapi/tests/http-examples/newsitem.resp
+++ b/src/plone/restapi/tests/http-examples/newsitem.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/newsitem/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/newsitem/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/newsitem/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/search_fullobjects.resp b/src/plone/restapi/tests/http-examples/search_fullobjects.resp
index e4f5bf0ac5..12674a345d 100644
--- a/src/plone/restapi/tests/http-examples/search_fullobjects.resp
+++ b/src/plone/restapi/tests/http-examples/search_fullobjects.resp
@@ -21,6 +21,9 @@ Content-Type: application/json
                 "navigation": {
                     "@id": "http://localhost:55001/plone/doc1/@navigation"
                 },
+                "navroot": {
+                    "@id": "http://localhost:55001/plone/doc1/@navroot"
+                },
                 "types": {
                     "@id": "http://localhost:55001/plone/doc1/@types"
                 },
diff --git a/src/plone/restapi/tests/http-examples/site_get.req b/src/plone/restapi/tests/http-examples/site_get.req
new file mode 100644
index 0000000000..2c0e40f0e2
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get.req
@@ -0,0 +1,3 @@
+GET /plone/@site HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/site_get.resp b/src/plone/restapi/tests/http-examples/site_get.resp
new file mode 100644
index 0000000000..e5f274d3de
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get.resp
@@ -0,0 +1,22 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@id": "http://localhost:55001/plone/@site",
+    "plone.allowed_sizes": [
+        "huge 1600:65536",
+        "great 1200:65536",
+        "larger 1000:65536",
+        "large 800:65536",
+        "teaser 600:65536",
+        "preview 400:65536",
+        "mini 200:65536",
+        "thumb 128:128",
+        "tile 64:64",
+        "icon 32:32",
+        "listing 16:16"
+    ],
+    "plone.robots_txt": "Sitemap: {portal_url}/sitemap.xml.gz\n\n# Define access-restrictions for robots/spiders\n# http://www.robotstxt.org/wc/norobots.html\n\n\n\n# By default we allow robots to access all areas of our site\n# already accessible to anonymous users\n\nUser-agent: *\nDisallow:\n\n\n\n# Add Googlebot-specific syntax extension to exclude forms\n# that are repeated for each piece of content in the site\n# the wildcard is only supported by Googlebot\n# http://www.google.com/support/webmasters/bin/answer.py?answer=40367&ctx=sibling\n\nUser-Agent: Googlebot\nDisallow: /*?\nDisallow: /*atct_album_view$\nDisallow: /*folder_factories$\nDisallow: /*folder_summary_view$\nDisallow: /*login_form$\nDisallow: /*mail_password_form$\nDisallow: /@@search\nDisallow: /*search_rss$\nDisallow: /*sendto_form$\nDisallow: /*summary_view$\nDisallow: /*thumbnail_view$\nDisallow: /*view$\n",
+    "plone.site_logo": null,
+    "plone.site_title": "Plone site"
+}
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.req b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.req
new file mode 100644
index 0000000000..5eae3bdfb1
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.req
@@ -0,0 +1,3 @@
+GET /plone/en?expand=navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
new file mode 100644
index 0000000000..cbdda29f64
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder.resp
@@ -0,0 +1,193 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@components": {
+        "actions": {
+            "@id": "http://localhost:55001/plone/en/@actions"
+        },
+        "aliases": {
+            "@id": "http://localhost:55001/plone/en/@aliases"
+        },
+        "breadcrumbs": {
+            "@id": "http://localhost:55001/plone/en/@breadcrumbs"
+        },
+        "contextnavigation": {
+            "@id": "http://localhost:55001/plone/en/@contextnavigation"
+        },
+        "navigation": {
+            "@id": "http://localhost:55001/plone/en/@navigation"
+        },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/en/@navroot",
+            "navroot": {
+                "@components": {
+                    "actions": {
+                        "@id": "http://localhost:55001/plone/en/@actions"
+                    },
+                    "aliases": {
+                        "@id": "http://localhost:55001/plone/en/@aliases"
+                    },
+                    "breadcrumbs": {
+                        "@id": "http://localhost:55001/plone/en/@breadcrumbs"
+                    },
+                    "contextnavigation": {
+                        "@id": "http://localhost:55001/plone/en/@contextnavigation"
+                    },
+                    "navigation": {
+                        "@id": "http://localhost:55001/plone/en/@navigation"
+                    },
+                    "navroot": {
+                        "@id": "http://localhost:55001/plone/en/@navroot"
+                    },
+                    "translations": {
+                        "@id": "http://localhost:55001/plone/en/@translations"
+                    },
+                    "types": {
+                        "@id": "http://localhost:55001/plone/en/@types"
+                    },
+                    "workflow": {
+                        "@id": "http://localhost:55001/plone/en/@workflow"
+                    }
+                },
+                "@id": "http://localhost:55001/plone/en",
+                "@type": "LRF",
+                "UID": "00000000000000000000000000000001",
+                "allow_discussion": false,
+                "contributors": [],
+                "created": "1995-07-31T13:45:00",
+                "creators": [
+                    "admin"
+                ],
+                "description": "",
+                "effective": null,
+                "exclude_from_nav": true,
+                "expires": null,
+                "id": "en",
+                "is_folderish": true,
+                "items": [
+                    {
+                        "@id": "http://localhost:55001/plone/en/assets",
+                        "@type": "LIF",
+                        "description": "",
+                        "review_state": "published",
+                        "title": "Assets",
+                        "type_title": "Language Independent Folder"
+                    },
+                    {
+                        "@id": "http://localhost:55001/plone/en/test-document",
+                        "@type": "Document",
+                        "description": "",
+                        "review_state": "private",
+                        "title": "Test document",
+                        "type_title": "Page"
+                    }
+                ],
+                "items_total": 2,
+                "language": {
+                    "title": "English",
+                    "token": "en"
+                },
+                "layout": "folder_listing",
+                "lock": {},
+                "modified": "1995-07-31T17:30:00",
+                "next_item": {
+                    "@id": "http://localhost:55001/plone/de",
+                    "@type": "LRF",
+                    "description": "",
+                    "title": "Deutsch",
+                    "type_title": "Language Root Folder"
+                },
+                "parent": {
+                    "@id": "http://localhost:55001/plone",
+                    "@type": "Plone Site",
+                    "description": "",
+                    "title": "Plone site",
+                    "type_title": "Plone Site"
+                },
+                "previous_item": {},
+                "review_state": "published",
+                "rights": "",
+                "subjects": [],
+                "title": "English",
+                "type_title": "Language Root Folder",
+                "version": "current",
+                "working_copy": null,
+                "working_copy_of": null
+            }
+        },
+        "translations": {
+            "@id": "http://localhost:55001/plone/en/@translations"
+        },
+        "types": {
+            "@id": "http://localhost:55001/plone/en/@types"
+        },
+        "workflow": {
+            "@id": "http://localhost:55001/plone/en/@workflow"
+        }
+    },
+    "@id": "http://localhost:55001/plone/en",
+    "@type": "LRF",
+    "UID": "00000000000000000000000000000001",
+    "allow_discussion": false,
+    "contributors": [],
+    "created": "1995-07-31T13:45:00",
+    "creators": [
+        "admin"
+    ],
+    "description": "",
+    "effective": null,
+    "exclude_from_nav": true,
+    "expires": null,
+    "id": "en",
+    "is_folderish": true,
+    "items": [
+        {
+            "@id": "http://localhost:55001/plone/en/assets",
+            "@type": "LIF",
+            "description": "",
+            "review_state": "published",
+            "title": "Assets",
+            "type_title": "Language Independent Folder"
+        },
+        {
+            "@id": "http://localhost:55001/plone/en/test-document",
+            "@type": "Document",
+            "description": "",
+            "review_state": "private",
+            "title": "Test document",
+            "type_title": "Page"
+        }
+    ],
+    "items_total": 2,
+    "language": {
+        "title": "English",
+        "token": "en"
+    },
+    "layout": "folder_listing",
+    "lock": {},
+    "modified": "1995-07-31T17:30:00",
+    "next_item": {
+        "@id": "http://localhost:55001/plone/de",
+        "@type": "LRF",
+        "description": "",
+        "title": "Deutsch",
+        "type_title": "Language Root Folder"
+    },
+    "parent": {
+        "@id": "http://localhost:55001/plone",
+        "@type": "Plone Site",
+        "description": "",
+        "title": "Plone site",
+        "type_title": "Plone Site"
+    },
+    "previous_item": {},
+    "review_state": "published",
+    "rights": "",
+    "subjects": [],
+    "title": "English",
+    "type_title": "Language Root Folder",
+    "version": "current",
+    "working_copy": null,
+    "working_copy_of": null
+}
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.req b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.req
new file mode 100644
index 0000000000..3574d72d7e
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.req
@@ -0,0 +1,3 @@
+GET /plone/en/test-document?expand=navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
new file mode 100644
index 0000000000..fdd9f28b64
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_lang_folder_content.resp
@@ -0,0 +1,183 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@components": {
+        "actions": {
+            "@id": "http://localhost:55001/plone/en/test-document/@actions"
+        },
+        "aliases": {
+            "@id": "http://localhost:55001/plone/en/test-document/@aliases"
+        },
+        "breadcrumbs": {
+            "@id": "http://localhost:55001/plone/en/test-document/@breadcrumbs"
+        },
+        "contextnavigation": {
+            "@id": "http://localhost:55001/plone/en/test-document/@contextnavigation"
+        },
+        "navigation": {
+            "@id": "http://localhost:55001/plone/en/test-document/@navigation"
+        },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/en/test-document/@navroot",
+            "navroot": {
+                "@components": {
+                    "actions": {
+                        "@id": "http://localhost:55001/plone/en/@actions"
+                    },
+                    "aliases": {
+                        "@id": "http://localhost:55001/plone/en/@aliases"
+                    },
+                    "breadcrumbs": {
+                        "@id": "http://localhost:55001/plone/en/@breadcrumbs"
+                    },
+                    "contextnavigation": {
+                        "@id": "http://localhost:55001/plone/en/@contextnavigation"
+                    },
+                    "navigation": {
+                        "@id": "http://localhost:55001/plone/en/@navigation"
+                    },
+                    "navroot": {
+                        "@id": "http://localhost:55001/plone/en/@navroot"
+                    },
+                    "translations": {
+                        "@id": "http://localhost:55001/plone/en/@translations"
+                    },
+                    "types": {
+                        "@id": "http://localhost:55001/plone/en/@types"
+                    },
+                    "workflow": {
+                        "@id": "http://localhost:55001/plone/en/@workflow"
+                    }
+                },
+                "@id": "http://localhost:55001/plone/en",
+                "@type": "LRF",
+                "UID": "00000000000000000000000000000001",
+                "allow_discussion": false,
+                "contributors": [],
+                "created": "1995-07-31T13:45:00",
+                "creators": [
+                    "admin"
+                ],
+                "description": "",
+                "effective": null,
+                "exclude_from_nav": true,
+                "expires": null,
+                "id": "en",
+                "is_folderish": true,
+                "items": [
+                    {
+                        "@id": "http://localhost:55001/plone/en/assets",
+                        "@type": "LIF",
+                        "description": "",
+                        "review_state": "published",
+                        "title": "Assets",
+                        "type_title": "Language Independent Folder"
+                    },
+                    {
+                        "@id": "http://localhost:55001/plone/en/test-document",
+                        "@type": "Document",
+                        "description": "",
+                        "review_state": "private",
+                        "title": "Test document",
+                        "type_title": "Page"
+                    }
+                ],
+                "items_total": 2,
+                "language": {
+                    "title": "English",
+                    "token": "en"
+                },
+                "layout": "folder_listing",
+                "lock": {},
+                "modified": "1995-07-31T17:30:00",
+                "next_item": {
+                    "@id": "http://localhost:55001/plone/de",
+                    "@type": "LRF",
+                    "description": "",
+                    "title": "Deutsch",
+                    "type_title": "Language Root Folder"
+                },
+                "parent": {
+                    "@id": "http://localhost:55001/plone",
+                    "@type": "Plone Site",
+                    "description": "",
+                    "title": "Plone site",
+                    "type_title": "Plone Site"
+                },
+                "previous_item": {},
+                "review_state": "published",
+                "rights": "",
+                "subjects": [],
+                "title": "English",
+                "type_title": "Language Root Folder",
+                "version": "current",
+                "working_copy": null,
+                "working_copy_of": null
+            }
+        },
+        "translations": {
+            "@id": "http://localhost:55001/plone/en/test-document/@translations"
+        },
+        "types": {
+            "@id": "http://localhost:55001/plone/en/test-document/@types"
+        },
+        "workflow": {
+            "@id": "http://localhost:55001/plone/en/test-document/@workflow"
+        }
+    },
+    "@id": "http://localhost:55001/plone/en/test-document",
+    "@type": "Document",
+    "UID": "SomeUUID000000000000000000000001",
+    "allow_discussion": false,
+    "changeNote": "",
+    "contributors": [],
+    "created": "1995-07-31T13:45:00",
+    "creators": [
+        "test_user_1_"
+    ],
+    "description": "",
+    "effective": null,
+    "exclude_from_nav": false,
+    "expires": null,
+    "id": "test-document",
+    "is_folderish": false,
+    "language": {
+        "title": "English",
+        "token": "en"
+    },
+    "layout": "document_view",
+    "lock": {
+        "locked": false,
+        "stealable": true
+    },
+    "modified": "1995-07-31T17:30:00",
+    "next_item": {},
+    "parent": {
+        "@id": "http://localhost:55001/plone/en",
+        "@type": "LRF",
+        "description": "",
+        "review_state": "published",
+        "title": "English",
+        "type_title": "Language Root Folder"
+    },
+    "previous_item": {
+        "@id": "http://localhost:55001/plone/en/assets",
+        "@type": "LIF",
+        "description": "",
+        "title": "Assets",
+        "type_title": "Language Independent Folder"
+    },
+    "relatedItems": [],
+    "review_state": "private",
+    "rights": "",
+    "subjects": [],
+    "table_of_contents": null,
+    "text": null,
+    "title": "Test document",
+    "type_title": "Page",
+    "version": "current",
+    "versioning_enabled": true,
+    "working_copy": null,
+    "working_copy_of": null
+}
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_navroot.req b/src/plone/restapi/tests/http-examples/site_get_expand_navroot.req
new file mode 100644
index 0000000000..36c802e247
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_navroot.req
@@ -0,0 +1,3 @@
+GET /plone/?expand=navroot HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/site_get_expand_navroot.resp b/src/plone/restapi/tests/http-examples/site_get_expand_navroot.resp
new file mode 100644
index 0000000000..00a8775fa7
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/site_get_expand_navroot.resp
@@ -0,0 +1,191 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+    "@components": {
+        "actions": {
+            "@id": "http://localhost:55001/plone/@actions"
+        },
+        "aliases": {
+            "@id": "http://localhost:55001/plone/@aliases"
+        },
+        "breadcrumbs": {
+            "@id": "http://localhost:55001/plone/@breadcrumbs"
+        },
+        "contextnavigation": {
+            "@id": "http://localhost:55001/plone/@contextnavigation"
+        },
+        "navigation": {
+            "@id": "http://localhost:55001/plone/@navigation"
+        },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/@navroot",
+            "navroot": {
+                "@components": {
+                    "actions": {
+                        "@id": "http://localhost:55001/plone/@actions"
+                    },
+                    "aliases": {
+                        "@id": "http://localhost:55001/plone/@aliases"
+                    },
+                    "breadcrumbs": {
+                        "@id": "http://localhost:55001/plone/@breadcrumbs"
+                    },
+                    "contextnavigation": {
+                        "@id": "http://localhost:55001/plone/@contextnavigation"
+                    },
+                    "navigation": {
+                        "@id": "http://localhost:55001/plone/@navigation"
+                    },
+                    "navroot": {
+                        "@id": "http://localhost:55001/plone/@navroot"
+                    },
+                    "types": {
+                        "@id": "http://localhost:55001/plone/@types"
+                    },
+                    "workflow": {
+                        "@id": "http://localhost:55001/plone/@workflow"
+                    }
+                },
+                "@id": "http://localhost:55001/plone",
+                "@type": "Plone Site",
+                "UID": "55c25ebc220d400393574f37d648727c",
+                "allow_discussion": null,
+                "contributors": [],
+                "creators": [
+                    "admin"
+                ],
+                "description": "",
+                "effective": null,
+                "exclude_from_nav": false,
+                "expires": null,
+                "id": "plone",
+                "is_folderish": true,
+                "items": [
+                    {
+                        "@id": "http://localhost:55001/plone/en",
+                        "@type": "LRF",
+                        "description": "",
+                        "review_state": "published",
+                        "title": "English",
+                        "type_title": "Language Root Folder"
+                    },
+                    {
+                        "@id": "http://localhost:55001/plone/de",
+                        "@type": "LRF",
+                        "description": "",
+                        "review_state": "published",
+                        "title": "Deutsch",
+                        "type_title": "Language Root Folder"
+                    },
+                    {
+                        "@id": "http://localhost:55001/plone/es",
+                        "@type": "LRF",
+                        "description": "",
+                        "review_state": "published",
+                        "title": "Espa\u00f1ol",
+                        "type_title": "Language Root Folder"
+                    },
+                    {
+                        "@id": "http://localhost:55001/plone/fr",
+                        "@type": "LRF",
+                        "description": "",
+                        "review_state": null,
+                        "title": "Fran\u00e7ais",
+                        "type_title": "Language Root Folder"
+                    }
+                ],
+                "items_total": 4,
+                "language": {
+                    "title": "English",
+                    "token": "en"
+                },
+                "lock": {
+                    "locked": false,
+                    "stealable": true
+                },
+                "parent": {},
+                "relatedItems": [],
+                "review_state": null,
+                "rights": "",
+                "subjects": [],
+                "table_of_contents": null,
+                "text": null,
+                "title": "Plone site",
+                "type_title": "Plone Site"
+            }
+        },
+        "types": {
+            "@id": "http://localhost:55001/plone/@types"
+        },
+        "workflow": {
+            "@id": "http://localhost:55001/plone/@workflow"
+        }
+    },
+    "@id": "http://localhost:55001/plone",
+    "@type": "Plone Site",
+    "UID": "55c25ebc220d400393574f37d648727c",
+    "allow_discussion": null,
+    "contributors": [],
+    "creators": [
+        "admin"
+    ],
+    "description": "",
+    "effective": null,
+    "exclude_from_nav": false,
+    "expires": null,
+    "id": "plone",
+    "is_folderish": true,
+    "items": [
+        {
+            "@id": "http://localhost:55001/plone/en",
+            "@type": "LRF",
+            "description": "",
+            "review_state": "published",
+            "title": "English",
+            "type_title": "Language Root Folder"
+        },
+        {
+            "@id": "http://localhost:55001/plone/de",
+            "@type": "LRF",
+            "description": "",
+            "review_state": "published",
+            "title": "Deutsch",
+            "type_title": "Language Root Folder"
+        },
+        {
+            "@id": "http://localhost:55001/plone/es",
+            "@type": "LRF",
+            "description": "",
+            "review_state": "published",
+            "title": "Espa\u00f1ol",
+            "type_title": "Language Root Folder"
+        },
+        {
+            "@id": "http://localhost:55001/plone/fr",
+            "@type": "LRF",
+            "description": "",
+            "review_state": null,
+            "title": "Fran\u00e7ais",
+            "type_title": "Language Root Folder"
+        }
+    ],
+    "items_total": 4,
+    "language": {
+        "title": "English",
+        "token": "en"
+    },
+    "lock": {
+        "locked": false,
+        "stealable": true
+    },
+    "parent": {},
+    "relatedItems": [],
+    "review_state": null,
+    "rights": "",
+    "subjects": [],
+    "table_of_contents": null,
+    "text": null,
+    "title": "Plone site",
+    "type_title": "Plone Site"
+}
diff --git a/src/plone/restapi/tests/http-examples/siteroot.resp b/src/plone/restapi/tests/http-examples/siteroot.resp
index 13b18a2921..51b29477ff 100644
--- a/src/plone/restapi/tests/http-examples/siteroot.resp
+++ b/src/plone/restapi/tests/http-examples/siteroot.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/translations_link_on_post.resp b/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
index e5913da8d4..1a7755fb8b 100644
--- a/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
+++ b/src/plone/restapi/tests/http-examples/translations_link_on_post.resp
@@ -19,6 +19,9 @@ Location: http://localhost:55001/plone/de/mydocument
         "navigation": {
             "@id": "http://localhost:55001/plone/de/mydocument/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/de/mydocument/@navroot"
+        },
         "translations": {
             "@id": "http://localhost:55001/plone/de/mydocument/@translations"
         },
diff --git a/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp b/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
index 214585a4d2..632f563ad2 100644
--- a/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
+++ b/src/plone/restapi/tests/http-examples/workingcopy_baseline_get.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/document/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/document/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/document/@types"
         },
diff --git a/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp b/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
index a8168577b7..aa76ec7ac3 100644
--- a/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
+++ b/src/plone/restapi/tests/http-examples/workingcopy_wc_get.resp
@@ -18,6 +18,9 @@ Content-Type: application/json
         "navigation": {
             "@id": "http://localhost:55001/plone/copy_of_document/@navigation"
         },
+        "navroot": {
+            "@id": "http://localhost:55001/plone/copy_of_document/@navroot"
+        },
         "types": {
             "@id": "http://localhost:55001/plone/copy_of_document/@types"
         },
diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py
index 2103b1e2e3..0a057161ac 100644
--- a/src/plone/restapi/tests/test_documentation.py
+++ b/src/plone/restapi/tests/test_documentation.py
@@ -7,9 +7,6 @@
 from plone.app.discussion.interfaces import IDiscussionSettings
 from plone.app.discussion.interfaces import IReplies
 from plone.app.multilingual.interfaces import ITranslationManager
-from plone.app.testing import applyProfile
-from plone.app.testing import popGlobalRegistry
-from plone.app.testing import pushGlobalRegistry
 from plone.app.testing import setRoles
 from plone.app.testing import SITE_OWNER_NAME
 from plone.app.testing import SITE_OWNER_PASSWORD
@@ -24,7 +21,6 @@
 from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
 from plone.restapi.testing import PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING
 from plone.restapi.testing import PLONE_RESTAPI_ITERATE_FUNCTIONAL_TESTING
-from plone.restapi.testing import register_static_uuid_utility
 from plone.restapi.testing import RelativeSession
 from plone.restapi.tests.helpers import patch_addon_versions
 from plone.restapi.tests.helpers import patch_scale_uuid
@@ -34,9 +30,11 @@
 from zope.component import createObject
 from zope.component import getMultiAdapter
 from zope.component import getUtility
-from zope.component.hooks import getSite
 from zope.interface import alsoProvides
-
+from plone.app.testing import popGlobalRegistry
+from plone.app.testing import pushGlobalRegistry
+from plone.restapi.testing import register_static_uuid_utility
+from zope.component.hooks import getSite
 import collections
 import json
 import os
@@ -222,7 +220,6 @@ def setUp(self):
         super().setUp()
         self.document = self.create_document()
         alsoProvides(self.document, ITTWLockable)
-
         transaction.commit()
 
     def tearDown(self):
@@ -989,7 +986,9 @@ def test_documentation_users_searched_get(self):
             "location": "Cambridge, MA",
         }
         api.user.create(
-            email="noam.chomsky@example.com", username="noam", properties=properties
+            email="noam.chomsky@example.com",
+            username="noam",
+            properties=properties,
         )
         api.group.add_user(groupname="Reviewers", username="noam")
         transaction.commit()
@@ -1129,7 +1128,9 @@ def test_documentation_groups(self):
             "location": "Cambridge, MA",
         }
         api.user.create(
-            email="noam.chomsky@example.com", username="noam", properties=properties
+            email="noam.chomsky@example.com",
+            username="noam",
+            properties=properties,
         )
         api.group.add_user(groupname="ploneteam", username="noam")
         transaction.commit()
@@ -1158,7 +1159,9 @@ def test_documentation_groups_get(self):
             "location": "Cambridge, MA",
         }
         api.user.create(
-            email="noam.chomsky@example.com", username="noam", properties=properties
+            email="noam.chomsky@example.com",
+            username="noam",
+            properties=properties,
         )
         api.group.add_user(groupname="ploneteam", username="noam")
         transaction.commit()
@@ -1598,7 +1601,8 @@ def test_locking_lock(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token":'
+            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("lock", response)
@@ -1611,7 +1615,8 @@ def test_locking_lock_nonstealable_and_timeout(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token":'
+            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("lock_nonstealable_timeout", response)
@@ -1637,7 +1642,8 @@ def test_locking_refresh_lock(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token":'
+            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("refresh_lock", response)
@@ -1712,6 +1718,32 @@ def test_addons_install_specific_profile(self):
         )
         save_request_for_docs("addons_install_profile", response)
 
+    def test_site_navroot_get(self):
+        response = self.api_session.get("/@navroot")
+        save_request_and_response_for_docs("navroot_standard_site_get", response)
+
+    def test_site_content_navroot_get(self):
+        response = self.api_session.get("/front-page/@navroot")
+        save_request_and_response_for_docs(
+            "navroot_standard_site_content_get", response
+        )
+
+    def test_site_navroot_get_expansion(self):
+        response = self.api_session.get("/?expand=navroot")
+        save_request_and_response_for_docs(
+            "navroot_standard_site_get_expansion", response
+        )
+
+    def test_site_navroot_content_get_expansion(self):
+        response = self.api_session.get("/front-page?expand=navroot")
+        save_request_and_response_for_docs(
+            "navroot_standard_site_content_get_expansion", response
+        )
+
+    def test_site_get(self):
+        response = self.api_session.get("/@site")
+        save_request_and_response_for_docs("site_get", response)
+
 
 class TestDocumentationMessageTranslations(TestDocumentationBase):
 
@@ -2104,11 +2136,16 @@ class TestPAMDocumentation(TestDocumentationBase):
     def setUp(self):
         super().setUp()
 
-        language_tool = api.portal.get_tool("portal_languages")
-        language_tool.addSupportedLanguage("en")
-        language_tool.addSupportedLanguage("es")
-        language_tool.addSupportedLanguage("de")
-        applyProfile(self.portal, "plone.app.multilingual:default")
+        #
+        # We manually set the UIDs for LRFs here because the static uuid
+        # generator is not applied for LRFs.
+        # When we have tried to apply it for LRFs we have had several
+        # utility registration problems.
+        #
+        setattr(self.portal.en, "_plone.uuid", "00000000000000000000000000000001")
+        setattr(self.portal.es, "_plone.uuid", "00000000000000000000000000000002")
+        setattr(self.portal.fr, "_plone.uuid", "00000000000000000000000000000003")
+        setattr(self.portal.de, "_plone.uuid", "00000000000000000000000000000004")
 
         en_id = self.portal["en"].invokeFactory(
             "Document", id="test-document", title="Test document"
@@ -2120,9 +2157,6 @@ def setUp(self):
         self.es_content = self.portal["es"].get(es_id)
         transaction.commit()
 
-    def tearDown(self):
-        super().tearDown()
-
     def test_documentation_translations_post(self):
         response = self.api_session.post(
             f"{self.en_content.absolute_url()}/@translations",
@@ -2147,6 +2181,7 @@ def test_documentation_translations_post_by_uid(self):
     def test_documentation_translations_get(self):
         ITranslationManager(self.en_content).register_translation("es", self.es_content)
         transaction.commit()
+
         response = self.api_session.get(
             f"{self.en_content.absolute_url()}/@translations"
         )
@@ -2185,6 +2220,32 @@ def test_documentation_translation_locator(self):
         )
         save_request_and_response_for_docs("translation_locator", response)
 
+    def test_site_navroot_get(self):
+        response = self.api_session.get("/@navroot")
+        save_request_and_response_for_docs("navroot_site_get", response)
+
+    def test_site_navroot_language_folder_get(self):
+        response = self.api_session.get("/en/@navroot")
+        save_request_and_response_for_docs("navroot_lang_folder_get", response)
+
+    def test_site_navroot_language_content_get(self):
+        response = self.api_session.get("/en/test-document/@navroot")
+        save_request_and_response_for_docs("navroot_lang_content_get", response)
+
+    def test_site_expansion_navroot(self):
+        response = self.api_session.get("?expand=navroot")
+        save_request_and_response_for_docs("site_get_expand_navroot", response)
+
+    def test_site_expansion_navroot_language_folder(self):
+        response = self.api_session.get("/en?expand=navroot")
+        save_request_and_response_for_docs("site_get_expand_lang_folder", response)
+
+    def test_site_expansion_navroot_language_folder_content(self):
+        response = self.api_session.get("/en/test-document?expand=navroot")
+        save_request_and_response_for_docs(
+            "site_get_expand_lang_folder_content", response
+        )
+
 
 class TestIterateDocumentation(TestDocumentationBase):
 
@@ -2388,7 +2449,10 @@ def test_rules_enable(self):
         # Enable some rules
         url = "/@content-rules"
         self.api_session.post(url)
-        payload = {"form.button.Enable": True, "rule_ids": ["rule-1", "rule-2"]}
+        payload = {
+            "form.button.Enable": True,
+            "rule_ids": ["rule-1", "rule-2"],
+        }
         response = self.api_session.patch(url, json=payload)
         save_request_and_response_for_docs("rules_enable", response)
 
@@ -2396,7 +2460,10 @@ def test_rules_disable(self):
         # Disable some assigned rules
         url = "/@content-rules"
         self.api_session.post(url)
-        payload = {"form.button.Disable": True, "rule_ids": ["rule-1", "rule-2"]}
+        payload = {
+            "form.button.Disable": True,
+            "rule_ids": ["rule-1", "rule-2"],
+        }
         response = self.api_session.patch(url, json=payload)
         save_request_and_response_for_docs("rules_disable", response)
 
@@ -2404,7 +2471,10 @@ def test_rules_apply_subfolders(self):
         # Enable apply on subfolders
         url = "/@content-rules"
         self.api_session.post(url)
-        payload = {"form.button.Bubble": True, "rule_ids": ["rule-1", "rule-2"]}
+        payload = {
+            "form.button.Bubble": True,
+            "rule_ids": ["rule-1", "rule-2"],
+        }
         response = self.api_session.patch(url, json=payload)
         save_request_and_response_for_docs("rules_apply_subfolders", response)
 
@@ -2412,7 +2482,10 @@ def test_rules_disable_apply_subfolders(self):
         # Disable apply on subfolders
         url = "/@content-rules"
         self.api_session.post(url)
-        payload = {"form.button.NoBubble": True, "rule_ids": ["rule-1", "rule-2"]}
+        payload = {
+            "form.button.NoBubble": True,
+            "rule_ids": ["rule-1", "rule-2"],
+        }
         response = self.api_session.patch(url, json=payload)
         save_request_and_response_for_docs("rules_disable_apply_subfolders", response)
 
@@ -2448,7 +2521,10 @@ def test_controlpanels_crud_rules(self):
         save_request_and_response_for_docs(
             "controlpanels_post_rule_condition_portaltype", response
         )
-        payload = {"file_extension": "JPG", "type": "plone.conditions.FileExtension"}
+        payload = {
+            "file_extension": "JPG",
+            "type": "plone.conditions.FileExtension",
+        }
         response = self.api_session.post(url, json=payload)
         save_request_and_response_for_docs(
             "controlpanels_post_rule_condition_fileextension", response
@@ -2540,7 +2616,10 @@ def test_controlpanels_crud_rules(self):
         save_request_and_response_for_docs(
             "controlpanels_post_rule_action_mail", response
         )
-        payload = {"comment": "Some comment", "type": "plone.actions.Versioning"}
+        payload = {
+            "comment": "Some comment",
+            "type": "plone.actions.Versioning",
+        }
         response = self.api_session.post(url, json=payload)
         save_request_and_response_for_docs(
             "controlpanels_post_rule_action_versioning", response
diff --git a/src/plone/restapi/tests/test_services_navroot.py b/src/plone/restapi/tests/test_services_navroot.py
new file mode 100644
index 0000000000..327b48847b
--- /dev/null
+++ b/src/plone/restapi/tests/test_services_navroot.py
@@ -0,0 +1,264 @@
+# -*- coding: utf-8 -*-
+from plone.app.testing import setRoles
+from plone.app.testing import TEST_USER_ID
+from plone.restapi.testing import (
+    PLONE_RESTAPI_DX_FUNCTIONAL_TESTING,
+    PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING,
+)
+from plone.restapi.testing import RelativeSession
+from zope.component import getMultiAdapter
+from zope.interface import alsoProvides
+from plone.app.layout.navigation.interfaces import INavigationRoot
+
+import unittest
+from plone import api
+import transaction
+
+
+class TestServicesNavroot(unittest.TestCase):
+
+    layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
+
+    def setUp(self):
+        self.app = self.layer["app"]
+        self.portal = self.layer["portal"]
+        self.portal_url = self.portal.absolute_url()
+        setRoles(self.portal, TEST_USER_ID, ["Manager"])
+
+        api.content.create(
+            container=self.portal,
+            id="news",
+            title="News",
+            type="Folder",
+        )
+        api.content.create(
+            container=self.portal.news,
+            id="document",
+            title="Document",
+            type="Document",
+        )
+        api.content.transition(obj=self.portal.news, transition="publish")
+        api.content.transition(obj=self.portal.news.document, transition="publish")
+        transaction.commit()
+
+        self.api_session = RelativeSession(self.portal_url, test=self)
+        self.api_session.headers.update({"Accept": "application/json"})
+
+    def test_get_navroot(self):
+        response = self.api_session.get(
+            "/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal, self.layer["request"]), name="plone_portal_state"
+        )
+
+        self.assertIn("navroot", response.json())
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(response.json()["@id"], self.portal_url + "/@navroot")
+
+    def test_get_navroot_non_multilingual_navigation_root(self):
+        """test that the navroot is computed correctly when a section
+        implements INavigationRoot
+        """
+        alsoProvides(self.portal.news, INavigationRoot)
+        transaction.commit()
+
+        response = self.api_session.get(
+            "/news/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.news, self.layer["request"]),
+            name="plone_portal_state",
+        )
+
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["navroot"]["@id"],
+            portal_state.navigation_root_url(),
+        )
+
+    def test_get_navroot_non_multilingual_navigation_root_content(self):
+        """test that the navroot is computed correctly in a content inside a section
+        that implements INavigationRoot
+        """
+        alsoProvides(self.portal.news, INavigationRoot)
+        transaction.commit()
+
+        response = self.api_session.get(
+            "/news/document/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.news, self.layer["request"]),
+            name="plone_portal_state",
+        )
+
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["navroot"]["@id"],
+            portal_state.navigation_root_url(),
+        )
+
+
+class TestServicesNavrootMultilingual(unittest.TestCase):
+
+    layer = PLONE_RESTAPI_DX_PAM_FUNCTIONAL_TESTING
+
+    def setUp(self):
+        self.app = self.layer["app"]
+        self.portal = self.layer["portal"]
+        self.portal_url = self.portal.absolute_url()
+        setRoles(self.portal, TEST_USER_ID, ["Manager"])
+
+        api.content.create(
+            container=self.portal.en,
+            id="news",
+            title="News",
+            type="Folder",
+        )
+        api.content.create(
+            container=self.portal.en.news,
+            id="document",
+            title="Document",
+            type="Document",
+        )
+        api.content.transition(obj=self.portal.en.news, transition="publish")
+        api.content.transition(obj=self.portal.en.news.document, transition="publish")
+
+        self.api_session = RelativeSession(self.portal_url, test=self)
+        self.api_session.headers.update({"Accept": "application/json"})
+
+        transaction.commit()
+
+    def test_get_navroot_site(self):
+        response = self.api_session.get(
+            "/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal, self.layer["request"]), name="plone_portal_state"
+        )
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["@id"],
+            portal_state.navigation_root_url() + "/@navroot",
+        )
+
+    def test_get_navroot_language_folder(self):
+        response = self.api_session.get(
+            "/en/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.en, self.layer["request"]), name="plone_portal_state"
+        )
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["@id"],
+            portal_state.navigation_root_url() + "/@navroot",
+        )
+
+    def test_get_navroot_language_content(self):
+        response = self.api_session.get(
+            "/en/news/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.en.news, self.layer["request"]),
+            name="plone_portal_state",
+        )
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["navroot"]["@id"],
+            portal_state.navigation_root_url(),
+        )
+
+    def test_get_navroot_non_multilingual_navigation_root(self):
+        """test that the navroot is computed correctly when a section
+        implements INavigationRoot
+        """
+        alsoProvides(self.portal.en.news, INavigationRoot)
+        transaction.commit()
+
+        response = self.api_session.get(
+            "/en/news/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.en.news, self.layer["request"]),
+            name="plone_portal_state",
+        )
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["navroot"]["@id"],
+            portal_state.navigation_root_url(),
+        )
+
+    def test_get_navroot_non_multilingual_navigation_root_content(self):
+        """test that the navroot is computed correctly in a content inside a section
+        that implements INavigationRoot
+        """
+        alsoProvides(self.portal.en.news, INavigationRoot)
+        transaction.commit()
+
+        response = self.api_session.get(
+            "/en/news/document/@navroot",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal.en.news, self.layer["request"]),
+            name="plone_portal_state",
+        )
+        self.assertIn("navroot", response.json())
+
+        self.assertEqual(
+            response.json()["navroot"]["title"],
+            portal_state.navigation_root_title(),
+        )
+        self.assertEqual(
+            response.json()["navroot"]["@id"],
+            portal_state.navigation_root_url(),
+        )
diff --git a/src/plone/restapi/tests/test_services_site.py b/src/plone/restapi/tests/test_services_site.py
new file mode 100644
index 0000000000..1bd9069eb5
--- /dev/null
+++ b/src/plone/restapi/tests/test_services_site.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+from plone.app.testing import setRoles
+from plone.app.testing import TEST_USER_ID
+from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
+from plone.restapi.testing import RelativeSession
+from zope.component import getMultiAdapter
+
+import unittest
+
+
+class TestServicesSite(unittest.TestCase):
+
+    layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
+
+    def setUp(self):
+        self.app = self.layer["app"]
+        self.portal = self.layer["portal"]
+        self.portal_url = self.portal.absolute_url()
+        setRoles(self.portal, TEST_USER_ID, ["Manager"])
+
+        self.api_session = RelativeSession(self.portal_url, test=self)
+        self.api_session.headers.update({"Accept": "application/json"})
+
+    def test_get_site(self):
+        response = self.api_session.get(
+            "/@site",
+        )
+
+        self.assertEqual(response.status_code, 200)
+        portal_state = getMultiAdapter(
+            (self.portal, self.layer["request"]), name="plone_portal_state"
+        )
+        self.assertEqual(
+            response.json()["plone.site_title"], portal_state.portal_title()
+        )
+        self.assertIn("plone.site_logo", response.json())
+        self.assertIn("plone.robots_txt", response.json())
+        self.assertIn("plone.allowed_sizes", response.json())