1. 8
    Create Astro Content Collections with Zod for a Typesafe Blog
    7m 48s

Create Astro Content Collections with Zod for a Typesafe Blog

Lazar Nikolov
InstructorLazar Nikolov
Share this video with your friends

Social Share Links

Send Tweet

A blog isn't worth much if you don't have a place to put your content. In this lesson we'll dive deep into Astros content collections API which is a feature for organizing all of your content and ensuring when you create your content you add the proper data to your front matter.

To do this we'll create a content folder that contains a config.ts inside that config we'll use defineCollection from astro:content to declare what our blog data will look like. From here you can set a schema property and use zod to declare the shape of the data you'd like your content to be in.

When actually creating content, Astro will throw errors if you miss an attribute in your frontmatter that was set in your schema.

Astro also gives you an easy way to grab all the content you have with the getCollection function. We'll use this function to add links to our latests blog posts on the home page.

Instructor: [0:00] Welcome back. I hope you had fun during your first challenge. If you got stuck and want to check out the code, there's a link in the description.

[0:07] In this lesson, we're going to talk about content collections. Content collections in Astro are the best way to manage and author any type of content. They help you organize your content into documents, validate your front matter, all while having automatic TypeScript type safety.

[0:23] In this lesson we're going to create a content collection for our blog. Just like the public directory, Astro is also aware of the content directory inside source. This folder doesn't exist initially, so let's create it. Right click on source, new folder, content.

[0:39] Astro will look for a config.ts file inside of this folder. Let's create that file as well, config.ts. In this file, we're going to define our collections. Let's import the { defineCollection } from 'astro:content'. Then we're going to create a blog collection constant and assign it to the defineCollection result.

[1:06] You might get an error that claims that the Astro content package cannot be found, neither its type declarations. To fix that all you need to do is stop the dev server and run npm, run dev again. When you run it now, you're going to see this line, watching source/content for changes.

[1:25] That means Astro is now aware that we're going to be defining content collections, so it set up the content collection types for us and the error should be gone now. Let's proceed.

[1:36] Inside of the defineCollections method, we're going to pass an object that has a type property set to content. To register our collections, Astro expects our collections exported object with the collection name as the key and the collection itself as the value.

[1:53] Let's export a const collections which is going to be an object where the key is going to be the collection name and the value is going to be the collection itself. Now, Astro knows about our blog collection. Now let's define the schema. Let's jump at the import statement at the top and also import z from the same package.

[2:15] Z stands for zod, which is a TypeScript schema validation library that Astro uses under the hood to validate our front matter and provide us with typings. To define our schema, let's define the schema property and set it to z.object. This is how we define arbitrary objects in zod. This object is going to have a few properties.

[2:36] The first one is going to be the title and the type is going to be z.string. Then we're going to have tags which is going to be a z.array of z.string or a string array, and also we're going to have a date which is going to be z.date. This is how we define schema types using Zod. It's very similar to how we defined our props using TypeScript, and this is enough for this schema.

[3:01] To start writing articles, we should create a new folder inside of the content and name it with the same name as our collection. In our case, it's going to be blog. Inside of this folder, we can create our articles now. Let's say hello-world.md for our markdown. First, we're going to define the front matter.

[3:23] We can do that by adding three dashes, just like we did for the content scripts. The front matter will require us to provide values for the properties that we defined in our schema. Let's start with the title. We can set this to helloworld. Then we define the tags which is going to be a string array so hello and then world.

[3:45] Then of course the date, which is going to be a string but in a date format. Something like 2023-09 for September 18 for 18th of September. After we define the front matter, we can simply write our markdown. I'm just going to paste some dummy text inside.

[4:04] Aside from the config file, Astro also provides us with a few more methods for fetching our content. Let's use them to list our articles on the home page below the recent blog posts. Let's open the index page and scroll all the way to the top.

[4:19] First, we're going to import the getCollection method from the Astro content package. This method will return all entries in a given collection. To get our posts, we can define our posts constant invoke the getCollection method, and pass the blog collection name.

[4:40] Since this returns a promise, we need to await it. Using await at the top level is also allowed in Astro. The posts constant now is an array of our blog entries. Let's scroll down to the ordered list element and loop through the posts.

[4:57] For every post, we're going to create a list item element. Inside of the list item, we're going to add our link component. Of course, we need to import it.

[5:09] Let's add the href to a template string that's going to post to /blog/ and then the slug. If you do post. and open IntelliSense, we'll see that there are several properties under the post variable. If we go down, we can see that the slug property is there too.

[5:28] Let's pick that for the URL. The data property holds the front matter data that we defined. Let's add it as the first child, post.data.title. We can also create a span next to the title which is going to render the post.data.date. Since this is a date object, we need to convert it to a UTC string and also slice the last 13 characters.

[5:55] If we save this, we'll see that we have the article, Hello World, followed by the Monday 18th of September 2023. Let's play with the layout a little bit. Let's make the date gray, so let's add text gray 400. Let's add a class to the link element of flex and justify between so that it pushes the date to the right.

[6:19] Let's create a new markdown file. Let's name this AstroRocks.MD. Since our dev server supports hot module replacement, Astro automatically refreshes the website, and now we see an error saying that the content entry front matter does not match the schema. This is thetype safety that I was talking about at the beginning of this lesson.

[6:42] Let's define it. Open the three dashes to define the front matter. We'll set the title to Astro Rocks. We'll set the tags to Astro Rocks and also the dates to, let's use the same date, and provide some markdown inside. Now we can see that Astro Rocks our new article is part of the list as well. Cool.

[7:06] Let's do a recap. Astro's content collections enables us to create and manage all sorts of content within our website. Everything we put inside source/folder will be treated as content. We defined our own content in the config.ts file by using the defineCollections method and z for Zod to define our schema.

[7:28] We created our content as markdown files that also have a front matter at the top. To retrieve the content we use the getCollection method which returned an array of our posts and their data. We looped through the array and rendered a list of our blog posts that showed the title and the date.