getMenu function fails to fetch menu.
Package containing the bug
next-drupal (NPM package)
Describe the bug
I am getting an error Error: Resource of type 'menu_items' not found. on trying to fetch menus with getMenu.
After debugging i see that buildEndpoint generates /jsonapi as an endpoint to fetch menus rather than /jsonapi/menu_items/{menu}
Fix:
getMenu should call the buildEndpoint as below by concatenating the path rather than passing menu_items as a resourceType.
const endpoint = await this.buildEndpoint({
locale:
options?.locale !== options?.defaultLocale ? options.locale : undefined,
path: `/menu_items/${menuName}`,
searchParams: options.params,
})
I would like to help and provide a fix/PR for this but I would like, if possible, feedback on what's the best approach:
- Call the endpoint without the resourceType parameter? Like presented by @Danishkhurshid
- Add the resource to JSON:API Menu Items module? And maybe list all available menus?
Has there been any progress here? I am trying to upgrade to next drupal v 2.0.0 and this is a potential blocker.
Running into the same issue as other folks here, specifically in my pages router usage (but haven't tested in app router yet).
I've got a fix for my own lib/drupal.ts file, should others find it useful. Basically just extending the base NextDrupalPages implementation to fix the issue in getMenu method.
import { DrupalMenuItem, DrupalMenuItemId, JsonApiOptions, JsonApiWithCacheOptions, JsonApiWithNextFetchOptions, NextDrupalPages } from 'next-drupal';
/**
* Recreate DrupalMenuTree from next-drupal (this is not exported from the library)
* https://github.com/chapter-three/next-drupal/blob/main/packages/next-drupal/src/menu-tree.ts
*/
class DrupalMenuTree<
T extends {
id: DrupalMenuItemId;
parent: DrupalMenuItemId;
items?: T[];
} = DrupalMenuItem,
> extends Array {
parentId: DrupalMenuItemId;
depth: number;
constructor(
menuItems: T[],
parentId: DrupalMenuItemId = '',
depth: number = 1,
) {
super();
this.parentId = parentId;
this.depth = depth;
if (menuItems?.length) {
this.build(menuItems, parentId);
}
}
build(menuItems: T[], parentId: DrupalMenuItemId) {
// Find the children of the specified parent.
const children = menuItems.filter(
(menuItem) => menuItem?.parent === parentId,
);
// Add each child to this Array.
for (const menuItem of children) {
const subtree = new DrupalMenuTree<T>(
menuItems,
menuItem.id,
this.depth + 1,
);
this.push({
...menuItem,
items: subtree.length ? subtree : undefined,
});
}
}
}
/**
* Extend the DrupalClient class to override the getMenu method.
* This is because the getMenu method in next-drupal is not working as expected.
* https://github.com/chapter-three/next-drupal/issues/752
*/
class CustomDrupalClient extends NextDrupalPages {
async getMenu<T = DrupalMenuItem>(
menuName: string,
options?: JsonApiOptions &
JsonApiWithCacheOptions &
JsonApiWithNextFetchOptions,
): Promise<{
items: T[];
tree: T[];
}> {
options = {
withAuth: this.withAuth,
deserialize: true,
params: {},
withCache: false,
...options,
};
const endpoint = await this.buildEndpoint({
locale:
options?.locale !== options?.defaultLocale ? options.locale : undefined,
path: `menu_items/${menuName}`,
searchParams: options.params,
});
this.debug(`Fetching menu items for ${menuName}.`);
const response = await this.fetch(endpoint, {
withAuth: options.withAuth,
next: options.next,
cache: options.cache,
});
await this.throwIfJsonErrors(response, 'Error while fetching menu items: ');
const data = await response.json();
const items = options.deserialize ? this.deserialize(data) : data;
const tree = new DrupalMenuTree(items);
const menu = {
items,
tree: tree.length ? tree : undefined,
};
return menu as { items: T[]; tree: T[] };
}
}
export const drupal = new CustomDrupalClient(
process.env.NEXT_PUBLIC_DRUPAL_BASE_URL || '',
{
auth: {
clientId: process.env.DRUPAL_CLIENT_ID || '',
clientSecret: process.env.DRUPAL_CLIENT_SECRET || '',
},
frontPage: process.env.DRUPAL_FRONT_PAGE || '/home',
},
);
Thank you very much for the share @Nuuou ! My colleague @vermario and I will look into this tomorrow to see if we can contribute as well.
@vonloxx menu_items is not an entity and therefore is not exposed in the /jsonapi index. Making menu_items available as a JSON:API resource like other entities seems like a lot of work, whereas we can address this more straightforwardly on the next-drupal side.
FYI: I've created a PR (#866) with the proposed solution.