#Reuse collection schema to validate object in .astro page

69 messages ยท Page 1 of 1 (latest)

violet geyser
#

I have a collection schema in config.ts for a collection pages like this: const pageSchema = defineCollection({ schema: ({ image }) => z.strictObject({ title: z.string(), description: z.string(), authors: z.array(z.string()), }), });

This validates page frontmatter in the pages collection.

I also have a page /src/pages/foo.astro that passes an object frontmatter to the layout.

Can I reuse pageSchema to validate the frontmatter object in foo.astro?

#

Reuse collection schema to validate object in .astro page

foggy forum
#

you could but astro is already validating it coming from the content collection isnt it?

violet geyser
foggy forum
#

alright

#

export schema and export type

#

then use it as props type

#

make sense?

violet geyser
#

I think? I'm intermediate experience in js, no experience with ts. But I'll see what I can glean by going through this. Is this it more or less?

First pic is collections config.ts, and you've added export type Article..., then using that type to create an Astro.props in the .astro page (where normally Astro.props would have been passed from the content collection entry)?

foggy forum
#

sort of

violet geyser
#

In the portion of config.ts you shared, you're not using defineCollection(). Do I need to extract my schemas out of defineCollection() to follow your suggestion?

foggy forum
#

you dont have to

violet geyser
#

Hmmm, ok. Thanks for your help, by the way!

In your code, you're destructuring Astro.props. But in my case, there are no Astro.props to destructure. I'm trying to define the props to pass to the page layout right there in the .astro page frontmatter

#
---
// /src/pages/test.astro
import PageLayout from '~/layouts/PageLayout.astro';

// this frontmatter object is what I want to validate against a collection schema
const frontmatter = {
  title: 'test',
  description: 'foo',
  authors: ['kermit', 'miss piggy'],
};
---

<PageLayout {frontmatter}>
  <p>hey</p>
</PageLayout>
foggy forum
#

like that?

violet geyser
#

No, that's similar to what I have in my [...slug].astro. In this case, test.astro is not pulling content from a collection at all. It's a standalone, but it needs to pass props to the same page layout as [...slug.astro].

It does so by passing an object to the layout with the same keys as a page collection entry. That object is named frontmatter but it's not actually a collection entry frontmatter/data, it's just there to pass props. So far so good, that works.

My question is how to validate the (bogus) frontmatter object using the collections schema

foggy forum
#

well if you really dont trust that typescript is already doing this for you

#

then call theSchemaYouExported.safeParse

violet geyser
#

Thanks for spending time with me on this.

Typescript isn't validating this object against the content collection schema, and I'm not sure why it would. There's no connection between the schema and this object, since this object isn't part of a content collection.

I tried .safeParse() before, but it fails:

import { z } from 'zod';
import fooSchema from '~/content/config';

const testObj = {
  title: 'test',
  description: 'foo bar',
  authors: ['vibe', 'yeah'],
};

console.log(fooSchema.safeParse(testObj));```

`TypeError: Cannot read properties of undefined (reading 'safeParse')`
#

I'll try spinning up something on Stackblitz

foggy forum
#

hmm it should be a zod schema

violet geyser
violet geyser
#

Hey @foggy forum if you have some minutes to check that stackblitz repro, I'd love to find out if there's any solution to this question. Hope it's okay that I pinged you

mossy willow
#

import {pageSchema} from '../content/config';

#

you're not exporting it as a default export

#

so you have to import it in curly braces

violet geyser
mossy willow
#

Ah yeah just saw that, I've seen these before. They're a bit weird but they usually come from import * as something imports. Let me have a look

#

ohh I see

#

the image helper is an astro thing

#

so you can't use that as a standalone schema

violet geyser
#

I was afraid that the image helper might be the hangup. Can i somehow pass the helper in, or use whatever Astro uses in validation that implements the helper?

mossy willow
#

No I don't think you can. But since you're importing the image, you actually already have the same datatype as if you used the schema helper

violet geyser
#

Ok so would that mean I'd need to break off the image part of the schema somehow, use safeParse() on that, and validate the image separately?

mossy willow
#

What are you actually trying to achieve with zod here? You can just put a type on your props object

violet geyser
#

I'm completely inexperienced with typescript, other than mucking around a little bit here and there. I wanted to reuse the zod schema as a matter of convenience, since it already exists and can be a single source of truth

#

The goal is just to be sure any props sent to the layout from an .astro page have the same schema as ones from collections

mossy willow
#

I think the best way to go is to define your props type in the layout component. My advice would be not to overengineer this. Define the shape of your input props and you should be fine. If your schema doesnt match at some point you will get an error and you can adjust it easily

violet geyser
#

Ok, I think I understand. Definitely overengineering here a bit! So does your suggestion mean skipping zod and /src/collections/config.ts for the page collection schema entirely, and only defining the shape with typescript in the layout?

mossy willow
#

Actuslly there is a better way

#

I forgot about this type helper but this actually lets you match the type to the currdnt schema

violet geyser
#

ohhhhhh, this? post: CollectionEntry<'blog'>; specifically <'blog'>?

mossy willow
#

Its the name of your collection

#

I forgot what it was in your case

violet geyser
#

Got it. Fantastic, I'll try it. So that basically creates what you were suggesting but by referencing the collection schema?

mossy willow
#

Yep

#

Should do

violet geyser
#

Awesome. Thank you very much!

mossy willow
#

No worries

tranquil pagodaBOT
#
If your issue is resolved, please help by doing the following two steps:
  1. From the ellipses (3-dot menu) in the top-right corner of the post (not the first message), edit the tags to include the Solved tag.
  2. From the same ellipses, select Close Post.
    Your post will still be available to search and can be re-opened simply by replying in it. Closing a post moves it down with older posts, so we can more easily focus on issues that still need to be resovled.
    Thank you for your help!
violet geyser
# mossy willow No worries

I'm getting somewhere with your suggestion, but the Props interface expects a full set of content entry props (page), not just the props that are defined in the content collection schema (page.data).

I changed the [...slug].astro (for content collection to send the full page, not just page.data, and adjusted the code in the layout accordingly. That works.

But I don't know how to send the full props of a content entry from index.astro.

#

The docs that you referenced say "A component can also pass an entire content entry as a prop." But this standalone Astro page isn't a content entry.

mossy willow
#

Just out of curiosity, are you developing this page in stackblitz or locally? If you want to use typescript I would recommend to use VS code locally, because then you can see typescript errors right in your code instead of having to run astro check.

violet geyser
violet geyser
mossy willow
#

No problem at all ๐Ÿ™‚ Yeah typescript is pretty awesome, but there can be a bit of a learning curve. You can always come here and ask questions if you're stuck!

violet geyser
mossy willow
#

Hahaha, that's a good project ๐Ÿ™‚ Typescript honestly makes your project better. Not every error it throws at you is always a problem, but it also surfaces real issues that are much harder to catch with plain JS. So good luck with that!