What are the best techniques for streamlining nested objects with Zod.js?

As a newcomer to zod.js, I have found that the DataSchema function is extremely helpful in verifying API data types and simplifying the API response easily.

However, I'm curious if there is a way to streamline the data transformation process for myExpectedData directly within the zod component (without using the array map method)?

Below is a snippet of my code:

const apiUrl = 'https://api.jikan.moe/v4/top/anime';

const DataSchema = z.array(
    z.object({
        mal_id: z.number().nullable(),
        images: z.object({
            jpg: z.object({
                    image_url: z.string().nullable()
                }

            )
        })
    })
)

type DataSchema = z.infer < typeof DataSchema > ;

async function fetchTopAnime() {
    try {
        const response = await axios.get(apiUrl);
        const rawData = response.data
        const AnimeData = DataSchema.parse(rawData.data)

        const myExpectedData = AnimeData.map((el) => {
            return {
                ...el,
                images: el.images.jpg.image_url
            }
        })

        console.log(myExpectedData);
    } catch (error) {
        console.error(`Error fetching data: ${error}`);
    }
}

fetchTopAnime();

Answer №1

If you want to apply transformations to your data, consider using Zod's transform method:

To customize your data post-parsing, utilize the transform method.

const stringToNumber = z.string().transform((val) => val.length);

stringToNumber.parse("string"); // => 6

[...]

In your scenario:

const DataSchema = z.array(
  z.object({
    mal_id: z.number().nullable(),
    images: z
      .object({
        jpg: z.object({
          image_url: z.string().nullable(),
        }),
      })
      .transform((images) => images.jpg.image_url),
  })
)

You may also choose to transform the "item" object in this way:

const DataSchema = z.array(
  z
    .object({
      mal_id: z.number().nullable(),
      images: z.object({
        jpg: z.object({
          image_url: z.string().nullable(),
        }),
      }),
    })
    .transform((item) => ({
      ...item,
      images: item.images.jpg.image_url,
    }))
)

...or even apply transformations at the array level:

const DataSchema = z
  .array(
    z.object({
      mal_id: z.number().nullable(),
      images: z.object({
        jpg: z.object({
          image_url: z.string().nullable(),
        }),
      }),
    })
  )
  .transform((items) =>
    items.map((item) => ({
      ...item,
      images: item.images.jpg.image_url,
    }))
  )

For better clarity, it is recommended to perform transformations close to the relevant fields. The first option tends to be clearer in this regard.

(Alternatively, if there's always a maximum of one image, you could opt for the second option and rename the field from images to something like image:

const DataSchema = z.array(
  z
    .object({
      mal_id: z.number().nullable(),
      images: z.object({
        jpg: z.object({
          image_url: z.string().nullable(),
        }),
      }),
    })
    .transform((item) => ({
      mal_id: item.mal_id,
      image: item.images.jpg.image_url,
    }))
)

Just a little side note.)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing the Replace function just once

I am currently using the Avada Theme on Wordpress and I am attempting to use jQuery to translate the social media privacy labels/content. Everything is working smoothly except for one issue. Below is the HTML code: function translate() { jQuery(".fus ...

Error encountered when attempting to perform a Fetch POST request with same-origin credentials (Express & React)

I'm currently testing a login process in React that reaches an Express API route; the HTTP request is a POST made using fetch as shown below: const response = await fetch(`http://localhost:3001/login`, { method: "POST", mode: "same- ...

Facing an error response with the Javascript callout policy in Apigee. Any suggestions on fixing this issue?

This is the code snippet I'm using in my JavaScript callout policy var payload = JSON.parse(request.content); var headers = {'Content-Type' : 'application/json'}; var url = 'https://jsonplaceholder.typicode.com/posts'; va ...

Modify jQuery to update the background image of a data attribute when hovering over it

Something seems to be off with this topic. I am attempting to hover over a link and change the background image of a div element. The goal is to always display a different picture based on what is set in the data-rhomboid-img attribute. <div id="img- ...

What is the best way to conceal the button?

I'm working on a program that involves flipping cards and creating new ones using three components: App, CardEditor, and CardViewer. Within the CardEditor component, I am trying to implement a function that hides the button leading to CardViewer until ...

What is the best way to include attributes in an HTML element?

I've been researching how to dynamically add attributes to an HTML tag using jQuery. Consider the following initial HTML code: <input type="text" name="j_username" id="j_username" autocorrect="off" autocapitalize="off" style="background-image: lin ...

Having trouble with TypeScript error in React with Material-UI when trying to set up tabs?

I have developed my own custom accordion component hook, but I am encountering the following error export default const Tabs: OverridableComponent<TabsTypeMap<{}, ExtendButtonBase<ButtonBaseTypeMap<{}, "button">>>> Check ...

Struggling to connect the array of objects from the .ts file with the template (.html) in Angular

Inside this .ts file, I am populating the "mesMenus" array that I want to display in the .html file: export class MenusComponent{ mesMenus= new Array<Menu>(); constructor(private gMenuService:GestionMenuService){ this.gMenuService.onAdd ...

Modifying `msg.sender` in Solidity and Ether.js

I have a Smart Contract written in Solidity. Within this contract, there is a function called makeMarketItem. function makeMarketItem( address nftContract, uint256 tokenId, uint256 price ) public payable nonReentrant { IERC721(nftContract). ...

Can you provide guidance on how to specifically specify the type for the generics in this TypeScript function?

I've been diving into TypeScript and experimenting with mapped types to create a function that restricts users from extracting values off an object unless the keys exist. Take a look at the code below: const obj = { a: 1, b: 2, c: 3 } fun ...

Ways to clear away adhesive header and maintain its fixed position

I've been tinkering with my website, which you can find at this link: . I used the html5 up template for it, and the template came with a sticky header. However, when the site is viewed on a smaller screen, there's an ugly gap that forms between ...

The cucumber_report.json file will not update to reflect the most recent test steps

I have encountered an issue with the cucumber_reporter.json file not overwriting under the reports/html folder in my framework. To address this, I made changes to the cucumberOpts option within my config.ts file. By modifying the format setting to "json:./ ...

Material-UI React Native components: Injecting Styles without Props

import {createStyles, WithStyles} from "@material-ui/core"; const styles = (theme: Theme) => createStyles({ root: {} }); interface MyProps extends WithStyles<typeof styles> { } export class MyComponent extends Component<MyProps ...

Form a column containing both row object data and html code elements

I am in the process of creating a unique column within my table, allowing me to execute specific actions and generating HTML code based on the object defining the row. Being new to Angular, I believe I should utilize $compile, but I am unsure of how to pr ...

Hiding the C3 tooltip after engaging with it

I'm currently expanding my knowledge on utilizing C3.js for creating charts, and one aspect I'm focusing on is enhancing the tooltip functionality. Typically, C3 tooltips only appear when you hover over data points as demonstrated in this example ...

iPad problem resolved: Disable click hover and double-click issue

I'm experiencing a problem with my web application specifically on Safari for iPad. I have to click twice in order to actually perform the click on the <a> tag. The first click triggers a hover effect, similar to when you hover with a mouse on d ...

Could the long-term consequences of utilizing '--force' or '--legacy-peer-deps' be detrimental?

I'm currently working on a react-native project and encountering an error while trying to install the native-base library... npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: <a href="/cdn-cgi/l/email-prote ...

After being deployed on Vercel, React is mistakenly redirecting to the incorrect file, although it functions properly when

I'm a beginner in JavaScript and I recently created a React project. Everything was working smoothly in local development until I deployed the project on Vercel. The issue is when a user clicks on the "about button," instead of showing 'about.htm ...

Converting milliseconds to a valid date object using Angular form validation

I am facing an issue with form validation and milliseconds in my Angular application. It seems that Angular does not consider time in milliseconds as a valid date format, causing the angular.isDate(1418645071000) function to return false. How can I modify ...

What sets apart jQuery.ajax's dataType="json" from using JSON.parse() for parsing JSON data?

What is the difference between using dataType='json' and parsing response with JSON.parse(response) in jQuery Ajax? $.ajax({ url: path, type: 'POST', dataType: 'json', data: { block ...