Data fetching
Data fetching with SWR
Use
SWR for all data fetching. It provides caching,
revalidation, and a clean hook-based API.
jsx
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then((res) => res.json());
export default function Profile() {
const { data, error, isLoading } = useSWR(
'https://my-site.com/api/user',
fetcher,
);
if (error) return <div>Failed to load</div>;
if (isLoading) return <div>Loading...</div>;
return <div>Hello, {data.name}!</div>;
}
Fetching Drupal content with JSON:API
To fetch content from Drupal (e.g., articles, events, or other content types),
use the autoconfigured
from the
package combined
with
for query building.
Important: Do not fabricate JSON:API resource payloads in Workbench mocks.
Components that fetch data should render their real loading, empty, or error
states in Workbench unless the user explicitly asks for a static, non-fetching
preview shape.
jsx
import { getNodePath, JsonApiClient } from 'drupal-canvas';
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';
import useSWR from 'swr';
const Articles = () => {
const client = new JsonApiClient();
const { data, error, isLoading } = useSWR(
[
'node--article',
{
queryString: new DrupalJsonApiParams()
.addSort('created', 'DESC')
.getQueryString(),
},
],
([type, options]) => client.getCollection(type, options),
);
if (error) return 'An error has occurred.';
if (isLoading) return 'Loading...';
return (
<ul>
{data.map((article) => (
<li key={article.id}>
<a href={getNodePath(article)}>{article.title}</a>
</li>
))}
</ul>
);
};
export default Articles;
Including relationships with
When you need related entities (e.g., images, taxonomy terms), use
to fetch them in a single request.
Avoid circular references in JSON:API responses. SWR uses deep equality
checks to compare cached data, which fails with "too much recursion" errors when
the response contains circular references.
Do not include self-referential fields. Fields that reference the same
entity type being queried (e.g.,
on an article query)
create circular references: Article A references Article B, which references
back to Article A. If you need related content of the same type, fetch it in a
separate query.
Use to limit the response. Always specify only the fields you
need. This improves performance and helps avoid circular reference issues:
jsx
const params = new DrupalJsonApiParams();
params.addSort('created', 'DESC');
params.addInclude(['field_category', 'field_image']);
// Limit fields for each entity type
params.addFields('node--article', [
'title',
'created',
'field_category',
'field_image',
]);
params.addFields('taxonomy_term--categories', ['name']);
params.addFields('file--file', ['uri', 'url']);
Creating content list components
When building a component that displays a list of content items (e.g., a news
listing, event calendar, or resource library), follow this workflow:
Setup gate
Before any JSON:API discovery or content-type checks, verify local setup:
- Check that a file exists in the project root.
- If exists, verify is set. Read
if present; otherwise, use .
- Send an HTTP request to
{CANVAS_SITE_URL}/{CANVAS_JSONAPI_PREFIX}
. Success
means HTTP .
- If the request is successful, continue with Drupal data fetching.
- If the request is unsuccessful (or required values are missing), ask
the user whether they want to:
- Configure Drupal connectivity now, or
- Continue with static content instead of Drupal fetching.
- If the user chooses to configure connectivity, provide instructions:
CANVAS_SITE_URL=<their Drupal site URL>
CANVAS_JSONAPI_PREFIX=jsonapi
(optional; defaults to ) Then wait
for the user to confirm they updated , and test the request again.
- If the user chooses not to configure connectivity, proceed with static
content.
- Do not update Vite config () to troubleshoot connectivity.
Connectivity issues must be resolved via correct values and Drupal
site availability, not build tooling changes.
Step 1: Analyze the list structure
Examine the design to understand what data each list item needs:
- What fields are displayed (title, date, image, category, etc.)?
- How are items sorted (newest first, alphabetical, etc.)?
- Are there filters or pagination?
Step 2: Identify or request the content type
Before writing code, verify that an appropriate content type exists in Drupal:
-
Check the JSON:API endpoint of your local Drupal site (configured via
and
environment variables) to find
a content type that matches the required structure. Use a plain
request for this check, after passing the Setup gate.
-
If a matching content type exists, use it and note which fields are
available.
-
If no matching content type exists, stop and prompt the user to create
one. Provide:
- A suggested content type name
- The required field structure based on the list design
Step 3: Build the component
Create the content list component using JSON:API to fetch content. Only use
fields that actually exist on the content type—do not assume fields exist
without verifying.
Handling filters
If the list includes filters based on entity reference fields (e.g., filter by
category, filter by author):
- Do not hardcode filter options. Filter options should be fetched
dynamically using JSON:API.
- Fetch the available options for each filter (e.g., all taxonomy terms in a
vocabulary) and populate the filter UI from that data.
This ensures filters stay in sync with the actual content in Drupal and new
options appear automatically without code changes.