Skip to content

Deserializing Data

When adding images to our recipes grid, we had to do quite a bit of traversing to get the data we needed due to the structure of relationships and included data in JSON:API responses.

// Get field_media_image referenced on the recipe
const mediaId = recipe.relationships.field_media_image.data.id;
const mediaEntity = recipes.included.find((obj) => obj.id === mediaId);
// Get the thumbnail file entity referenced on field_media_image
const fileId = mediaEntity.relationships.thumbnail.data.id;
const alt = mediaEntity.relationships.thumbnail.data.meta.alt;
const fileEntity = recipes.included.find((obj) => obj.id === fileId);

We can simplify this by using the serializer option when creating our client instance, along with a library like Jsona. This will provide a simplified and flattened response when data is returned from the server.

The serializer Option

Revisiting the creation of our JsonApiClient instance, we can add an options object as the second argument. This object can include a serializer property, which can be used to transform the data provided by JSON:API .The provided serializer object can have two methods: deserializer and serializer. An instance of Jsona fits that signature.

Let’s update our client instance to use the Jsona serializer.

import { JsonApiClient } from "@drupal-api-client/json-api-client";
import { Jsona } from "jsona";
const client = new JsonApiClient("https://drupal-api-demo.party", {
serializer: new Jsona(),
});

Deserializing Data

Now that we have provided a compatible serializer, all data sourced from Drupal will be deserialized automatically.

import { JsonApiClient } from "@drupal-api-client/json-api-client";
const client = new JsonApiClient(
"https://drupal-api-demo.party", {
serializer: new Jsona(),
},
);
const recipes = await client.getCollection("node--recipe", {
queryString: "include=field_media_image.thumbnail",
});

Taking a look at the recipes object, you’ll see that the data is now flatter and easier to access. For example, field_media_image is now a direct property of the recipe data, and the thumbnail file is directly accessible from this media entity. We could get the thumbnail url for the first recipe result like this:

const thumbnailUrl = recipe[0].field_media_image.thumbnail.uri.url;

Refactoring the Recipe Grid

Let’s see the impact that working with deserialized data has on our recipe grid. We can refactor the grid to use this new flattened data structure.

Umami Recipes

Deep mediterranean quiche

Difficulty: medium

A delicious deep layered Mediterranean quiche with basil garnish View Recipe

Vegan chocolate and nut brownies

Difficulty: medium

A stack of chocolate and pecan brownies, sprinkled with pecan crumbs and crushed walnut, fresh out of the oven View Recipe

Super easy vegetarian pasta bake

Difficulty: easy

Cheesy pasta dish with vegetarian sausages and topped with mozzarella cheese and basil View Recipe

Watercress soup

Difficulty: easy

Watercress soup with a sprig of coriander as garnish in a white bowl with green trim View Recipe

Victoria sponge cake

Difficulty: easy

A classic, uncut Victoria sponge with a deep filling of butter cream and jam View Recipe

Gluten free pizza

Difficulty: medium

Olives, basil, and mozzarella top a gluten free pizza crust with marinara sauce View Recipe

Thai green curry

Difficulty: medium

A traditional bowl of creamy, aromatic Thai green curry with chunks of chicken in a small bowl with jasmine rice View Recipe

Crema catalana

Difficulty: medium

Typical Catalan dessert made from cream and egg yolks, covered with a traditional layer of caramelized sugar to provide a crispy contrast View Recipe

Fiery chili sauce

Difficulty: easy

An iridescent array of chilies, onions, and garlic, slowly sweating over a low heat View Recipe

Borscht with pork ribs

Difficulty: medium

Traditional Ukrainian soup with beets, tomatoes, and pork ribs View Recipe
---
import { JsonApiClient } from "@drupal-api-client/json-api-client";
import { Jsona } from "jsona";
const client = new JsonApiClient(
"https://drupal-api-demo.party", {
serializer: new Jsona(),
},
);
const recipes = await client.getCollection("node--recipe", {
queryString: "include=field_media_image.thumbnail",
});
---
<style>
.card-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1rem;
}
.card-grid .card {
display: flex;
flex-direction: column;
justify-content: space-between;
border: 2px solid var(--sl-color-text-accent);
margin-top: 0;
padding: 0.5rem;
}
</style>
<div>
<h2>Umami Recipes</h2>
<div class="card-grid">
{recipes.map((recipe) => (
<div class="card" key={recipe.id}>
<h4>{recipe.title}</h4>
<div>
<p>Difficulty: {recipe.field_difficulty}</p>
<img
src=`${client.baseUrl}${recipe.field_media_image.thumbnail.uri.url}`
alt={recipe.field_media_image.thumbnail.resourceIdObjMeta.alt}
/>
<a href={recipe.path.alias}>View Recipe</a>
</div>
</div>
))}
</div>
</div>

The end result is the same, so choose the option that is best for your team. Use the client default to work with the JSON:API response as is, or use the serializer option to work with a simplified object.

Serializing Data

In cases where you need serialize or re-serialize the data before sending it to the server, you will have access to the serializer method on the client instance. Below is an example of using Jsona’s serializer.

import { JsonApiClient } from "@drupal-api-client/json-api-client";
import { Jsona } from "jsona";
const client = new JsonApiClient("https://drupal-api-demo.party", {
serializer: new Jsona(),
});
// This recipe will be deserialized automatically
const recipe = await getResource(
"node--recipe",
"35f7cd32-2c54-49f2-8740-0b0ec2ba61f6",
);
// If we later need to re-serialize the recipe we can do so like this
const serializedRecipe = client.serializer.serialize({ stuff: recipe });

Since the signature of these serializer methods tend to vary, the JSON:API client doesn’t currently serialize data automatically, but it will be available for use if provided.

Additional Resources