Getting Objects

tldr; Pass the objectName parameter to getObject to get a deserialized collection of objects. Add the id parameter to get an individual object.

Edit Drupal State Quickstart

import { DrupalState } from '@gdwc/drupal-state';

const store = new DrupalState({
  apiBase: 'https://dev-ds-demo.pantheonsite.io',
  apiPrefix: 'jsonapi',
});

// If the object doesn't exist in local state, it will be fetched from the API
// and then added to the store
const recipesFromApi = await store.getObject({ objectName: 'node--recipe' });

// Since the object is already in local state as part of the recipes collection,
// this will be returned from the store without requiring a fetch from Drupal.
const recipeFromStore = await store.getObject({
  objectName: 'node--recipe',
  id: '33386d32-a87c-44b9-b66b-3dd0bfc38dca',
});

// To fetch an object with query string parameters, there are two options.
// pass in your query string parameters constructed as a string
// see https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/fetching-resources-get for more information
// on building query string parameters for Drupal's JSON:API
const recipeWithParams = await store.getObject({
  objectName: 'node--recipe',
  id: '33386d32-a87c-44b9-b66b-3dd0bfc38dca',
  params: 'include=field_recipe_category',
});

// You may have complicated query string parameters. In such cases we suggest using the
// drupal-jsonapi-params library https://www.npmjs.com/package/drupal-jsonapi-params
// which is also a dependency of this library.
// Note: DrupalState currently supports v1.x of drupal-jsonapi-params
// you may encounter errors if trying to use v2.x
import { DrupalJsonApiParams } from 'drupal-jsonapi-params';

// instantiate a new instance of DrupalJsonApiParams and add an include
const params = new DrupalJsonApiParams();
params.addInclude('field_recipe_category');

const recipeWithParams = await store.getObject({
  objectName: 'node--recipe',
  id: '33386d32-a87c-44b9-b66b-3dd0bfc38dca',
  // The object has the same name as the key, so we can omit the key.
  params,
});

// In some cases the data in the store is stale and a fresh fetch is required.
// To force Drupal to refresh the data, use the `refresh` option.
const recipeFromDrupal = await store.getObject({
  objectName: 'node--recipe',
  id: '33386d32-a87c-44b9-b66b-3dd0bfc38dca',
  refresh: true,
});

// If there is a collection with more than 50 entries, Drupal will automatically
// paginate results and return the first 50 items.
// To fetch all items in a collection, use the `all` option
const allArticlesFromApi = await store.getObject({
  objectName: 'node--ds_example',
  all: true,
});

// If your DrupalState store has valid credentials, all requests are authorized by default
// To make a request anonymous, use the `anon` option and set it to true
const anonRequest = await store.getObject({
  objectName: 'node--recipe',
  anon: true,
});

To better understand the advantages of Drupal State, below we will compare the process of interacting with these endpoints directly to taking the same approach using Drupal State’s helpers.

Without Drupal State

First, we’ll need to determine the endpoint to use. You may know this already, or you may know enough about Drupal’s JSON:API to construct it yourself. But if you don’t, you’ll need to make a request to the root API endpoint in order to retrieve this from an index of endpoints for all resources.

Edit Get Collection of Objects - Direct Fetch

// Fetch the API index
const apiIndex = await fetch('https://dev-ds-demo.pantheonsite.io')
  .then(response => response.json())
  .then(data => data)
  .catch(error => console.error('API index fetch failed', error));

// With the result, we can determine the recipes endpoint
console.log('recipes endpoint: ', apiIndex.links['node--recipes']);

We can now fetch the recipes collection from the API.

// Fetch recipes collection from API
const recipesFromApi = await fetch(apiIndex.links['node--recipe'].href)
  .then(response => response.json())
  .then(data => data)
  .catch(error => console.error('API fetch failed', error));

// With the result we can access an array of recipe objects
console.log('All recipes:', recipesFromApi.data);

Let’s say I wanted to access the instructions field for a recipe. We can access that field under the attributes for the recipe.

const instructions = recipesFromApi.data[0].attributes.field_recipe_instruction;

What if at some later point my application needs to get data for a specific recipe? I could fetch the data from the endpoint for that specific resource, but that will result in an additional request that could be avoided.

const recipeFromApi = await fetch(
  `${apiIndex.links['node--recipe'].href}/33386d32-a87c-44b9-b66b-3dd0bfc38dca`
)
  .then(response => response.json())
  .then(data => data)
  .catch(error => console.error('API fetch failed', error));

Alternatively, if I stored the data in application state, I could retrieve it from the recipes collection we previously requested. But I’d still have to either search for it, or store it in a way that allows for easy access within the data store.

// Filter for the resource in application state
const recipeFromState = recipesFromApi.data.filter(item => {
  return item['id'] === '33386d32-a87c-44b9-b66b-3dd0bfc38dca';
});

With Drupal State

Edit Drupal State Quickstart

import { DrupalState } from '@gdwc/drupal-state';

const store = new DrupalState({
  apiBase: 'https://dev-ds-demo.pantheonsite.io',
  apiPrefix: 'jsonapi',
});

// If the object doesn't exist in local state, it will be fetched from the API
// and then added to the store
const recipesFromApi = await store.getObject({ objectName: 'node--recipe' });

The code above will return a collection of recipes and store them in local state. As part of that process, Drupal State will also retrieve the root API index and store it in local state. This will allow it to determine the correct endpoint for recipes, and allow any other endpoint lookups to be performed without additional requests.

An array of recipe objects is returned, and we can access individual items.

const recipe = recipesFromApi[0];

Alternatively, now that the recipes collection is in local state, we can easily retrieve an individual recipe from the store without an additional request.

const recipeFromStore = await store.getObject({
  objectName: 'node--recipe',
  id: '33386d32-a87c-44b9-b66b-3dd0bfc38dca',
});

The resulting object is deserialized in order to simplify accessing data. For example, we can access the instructions field with:

const instructions = recipeFromStore.field_recipe_instruction;