Decoupled menus overview

Last updated on
19 August 2024

This documentation needs review. See "Help improve this page" in the sidebar.

Decoupled Menus provides the best way for JavaScript front ends to consume configurable menus managed in Drupal. This makes it easy for a front-end developer to consume that menu data in order to render a navigation instead of hardcoding it. This also means that non-developers can manage application menus without writing code!

This functionality is built into Drupal core, so you get all the other benefits that you would expect from the best CMS on the planet. This includes security, caching, and translations as well. You can actually serve multilingual menu data out to any number of decoupled applications with ease.

While this functionality can be used in many ways, there is one primary use case that Decoupled Menus is currently serving: menus that are global and static. This is a menu that will remain the same from page to page or screen to screen, and is intended to provide universal navigation options for decoupled applications. These menus are the same for all users.

In the future, decoupled menus functionality could be expanded to cover menus that are contextually aware. This would be a menu that may change based on the context of the page or the specific user. As an example, there may be specific menu items that are available based on the user and their role or access in the application. Additional discussion related to this concept can be found by consulting the following issue.

In addition to the back end functionality provided by the module, there are also tools available to make it easier to use the API data in the front end including libraries and web components.

Backend

Quickest way to have a working setup: drush, sqlite + built-in php server.

Setting up the Drupal backend

Use drush and a sqlite DB to setup the website.

composer create-project drupal/recommended-project:^10.1.x-dev decoupled

cd decoupled

composer require drush/drush

./vendor/bin/drush si demo_umami --db-url=sqlite://.ht.sqlite

Enable the linkset endpoint

It is possible to enable the linkset endpoint in site settings under Webservices on the configuration page. The url for this setting is /admin/config/services/linkset

Finding the setting on the configuration page

Enable the linkset endpoint

This enabled an new endpoint at system/menu/[menu system name]/linkset. This endpoint serves menu's as a linkset.

Serving Drupal

Use the built-in PHP server (use another terminal)

cd web
php -S localhost:8888 .ht.router.php

Getting Menu data

Menu data is available at /system/menu/[menu name]/linkset, where "[menu name]" is the machine name of the menu. For instance, to retrieve the main menu:

curl http://localhost:8888/system/menu/main/linkset

If your frontend is on a different domain than your backend, you can enable CORS headers to allow javascript requests to work from the frontend.

To access the menu data in a different language add the language prefix or language domain to the request. To get the menu in Spanish, add the es prefix to the URL.

curl http://localhost:8888/es/system/menu/main/linkset

 The endpoint respects user permissions, so you can only access the admin menu data when logged in with an appropriate user account.

curl http://localhost:8888/system/menu/admin/linkset

Sample response format

The format of the response follows the linkset IETF draft to allow some predictability on the structure of the response.

The menu data is returned in a flat array, the information in the drupal-menu-hierarchy makes it possible to render the structured menu.

{
  "linkset": [
    {
      "anchor": "\/system\/menu\/admin\/linkset",
      "item": [
        {
          "href": "\/en\/admin",
          "title": "Administration",
          "drupal-menu-hierarchy": [
            ".000"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure",
          "title": "Structure",
          "drupal-menu-hierarchy": [
            ".000.001"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure\/block",
          "title": "Block layout",
          "drupal-menu-hierarchy": [
            ".000.001.000"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure\/contact",
          "title": "Contact forms",
          "drupal-menu-hierarchy": [
            ".000.001.001"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure\/display-modes",
          "title": "Display modes",
          "drupal-menu-hierarchy": [
            ".000.001.003"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure\/display-modes\/form",
          "title": "Form modes",
          "drupal-menu-hierarchy": [
            ".000.001.003.000"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        },
        {
          "href": "\/en\/admin\/structure\/display-modes\/view",
          "title": "View modes",
          "drupal-menu-hierarchy": [
            ".000.001.003.001"
          ],
          "drupal-menu-machine-name": [
            "admin"
          ]
        }
      ]
    }
  ]
}

Help improve this page

Page status: Needs review

You can: