Overview

getSiteData() and getPageData() in the drupal-canvas package read synchronously from window.drupalSettings?.canvasData?.v0 — data that Drupal injects only when rendering a full page with the relevant canvas/canvasData.v0.* asset libraries attached. No HTTP endpoint exposes this data. Workbench runs as a local Vite dev server with no Drupal page render, so it cannot call these functions to get live site or page data.

Proposed resolution

PHP: new API route and controller

Add a route canvas.api.v0.site_data at GET /canvas/api/v0/site-data in canvas.routing.yml, following the same authentication and access pattern as other read-only Canvas API routes:

canvas.api.site_data:
  path: '/canvas/api/v0/site-data'
  defaults:
    _controller: 'Drupal\canvas\Controller\SiteDataController'
  requirements:
    _canvas_authentication_required: TRUE
    _canvas_ui_access: 'TRUE'
    _format: 'json'
  methods: [GET]
  options:
    canvas_external_api: true

Add \Drupal\canvas\Controller\SiteDataController. It calls all relevant CodeComponentDataProvider methods — the same methods already wired in ComponentSourceHooks::jsSettingsAlter() via ASSET_LIBRARY_METHOD_MAPPING — and returns a JsonResponse with the merged canvasData.v0 shape:

{
  "baseUrl": "https://example.com",
  "branding": { "homeUrl": "/", "siteName": "My Site", "siteSlogan": "" },
  "themeAssets": {
    "logo": { "url": "/themes/custom/my_theme/logo.svg" },
    "favicon": { "url": "/favicon.ico", "mimeType": "image/x-icon" }
  }
}

PHP: OAuth authentication coverage

Add canvas.api.site_data to the $named_routes array in \Drupal\canvas_oauth\Authentication\Provider\CanvasOauthAuthenticationProvider::applies(). The provider explicitly enumerates route names; it will not pick up the new route automatically. This ensures OAuth2 Bearer token requests from the CLI and Workbench are authenticated the same way as artifact upload and push lifecycle routes.

TypeScript: Workbench bootstrap via @drupal-canvas/vite-plugin

@drupal-canvas/vite-plugin already uses transformIndexHtml to build a window.drupalSettings = { canvasData: { v0: ... } } script tag and inject it into the page at bootstrap. It currently populates only baseUrl and jsonapiSettings from local environment config.

Extend the plugin so that when a Drupal site URL is available, it fetches /canvas/api/v0/canvas-data at bootstrap time (using the CLI's OAuth-authenticated HTTP client) and merges the response into the canvasData.v0 object before the script tag is emitted. Because Workbench uses @drupal-canvas/vite-plugin via vite-compat, this means window.drupalSettings.canvasData.v0 is fully populated before any component code runs — and the existing getSiteData() and getPageData() functions work with no changes.

The endpoint response includes jsonapiSettings (from CodeComponentDataProvider::getCanvasDataJsonApiSettingsV0()), so the jsonapiPrefix option and CANVAS_JSONAPI_PREFIX env var in the vite-plugin become unnecessary when the HTTP fetch is used — Workbench no longer needs that value configured separately.

User interface changes

None.

Issue fork canvas-3585327

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mglaman created an issue. See original summary.

penyaskito’s picture

Issue summary: View changes

Moved _format: 'json' to requirements.

mglaman’s picture

Issue summary: View changes

I forgot about vite-compat, thx balintbrews

mglaman’s picture

Issue summary: View changes

little bit about jsonapiSettings and simplifying config

mglaman’s picture

Status: Active » Needs review
effulgentsia’s picture

Status: Needs review » Needs work

Can we scope this down to only site data? Then the route name could be canvas.api.site_data and the path could be /canvas/api/v0/site-data.

Page data is more complicated because it's only meaningful if you somehow pass which page (which could be a Canvas page, a node, or some other Drupal page) you want it for. And most of the time within Canvas Workbench you'd want this mocked rather than fetched live: for example if you're viewing a component in isolation or if you're viewing a page that only exists locally and that you haven't pushed yet. Some of the time you might want to fetch it live (e.g., when viewing a page that you haven't made local changes to), but can we punt that to a followup, and just have Canvas Workbench mock the page data in all cases for now until we implement /canvas/api/v0/page-data in that followup issue?

mglaman’s picture

Title: Add HTTP API endpoint for canvasData.v0 to support useSiteData() and usePageData() in Workbench » Add HTTP API endpoint for canvasData.v0 to support useSiteData() in Workbench
Assigned: Unassigned » mglaman

Yeah that makes sense!

mglaman’s picture

Issue summary: View changes
mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review

Done! Reduced scope to just site data.

    $data = static::decodeResponse($response);
    self::assertArrayHasKey('baseUrl', $data);
    self::assertArrayHasKey('branding', $data);
    self::assertArrayHasKey('themeAssets', $data);
    self::assertArrayHasKey('jsonapiSettings', $data);
    self::assertArrayHasKey('siteName', $data['branding']);
    self::assertArrayNotHasKey('breadcrumbs', $data);
    self::assertArrayNotHasKey('mainEntity', $data);
    self::assertArrayNotHasKey('pageTitle', $data);
effulgentsia’s picture

This looks great on the PHP side, so I approved the MR, but I did not review the JS portion so am not setting this to RTBC.