Playing around with Sanity.io

palmiak

Maciek Palmowski

Posted on December 15, 2022

Playing around with Sanity.io

Sanity.io is one of the new cool kids regarding headless CMSs. I decided to give it a try and create almost precisely the same blog as the one you are reading.

What is Sanity.io

First of all, Sanity.io is a headless CMS. This means it's only responsible for storing the data, and it's up to us to connect it with a front end. We can use whatever we want here.

The CMS is fully configurable. Thanks to Sanity Studio, we can configure our CMS how we want - we just need to create schemas.

Sanity also gives us two ways to communicate with our application: GraphQL or GROQ. I just want to say that GROQ quickly became my favorite. It's like SQL and GraphQL had a baby.

Now that we know what Sanity.io is, it's time to code.

The plan

I plan to create a blog like the one you are just reading. This means we will need the following:

  • posts

  • navigation menus

  • setting page

  • categories

  • pages (although I skipped this as even now I'm almost not using this)

There are also some things that I decided not to add because it's just an experiment:

  • SEO settings

  • Open Graph data

  • SSR

Time to start modeling this content using Sanity Studio

Installation and some groundwork

Installation is pretty simple. Just follow the steps from the official guide, and everything should be up and running in a few minutes.

In my case, I also installed one addon - the markdown input field.

And here is the code repository. In the studio folder, you'll find everything related to Sanity. Apart from this folder, everything else is associated with Astro.

Adding schemas

My schema structure looks like this:

schemas
|-- documents
|-- objects
index.js
Enter fullscreen mode Exit fullscreen mode

The document folder is for post types, and the objects folder is for small bits that we will reuse from time to time.

For example, let me show you how to create a category schema. First, create an empty file category.js inside the schemas/documents folder. Then add this code inside:

export default {
    name: "category",
    type: "document",
    title: "Category",
    fields: [
        {
            name: "title",
            type: "string",
            title: "Title",
        },
        {
            name: "slug",
            type: "slug",
            title: "Slug",
            description:
                "Some frontends will require a slug to be set to be able to show the category",
            options: {
                source: "title",
                maxLength: 96,
            },
        },
    ],
};
Enter fullscreen mode Exit fullscreen mode

As you can see, it consists of two fields - Title and Slug.

Next, it's time to import it the index.js file:

import category from "./documents/category";

export const schemaTypes = [category];
Enter fullscreen mode Exit fullscreen mode

And is how our admin panel will look like:

You can browse the rest of the fields in the GitHub repo.

Connecting Sanity.io with Astro

Now, it's time to connect Sanity.io with Astro.

I won't go step-by-step because everything becomes simple if you understand how the GROQ language works.

First, we need to install the Sanity + Astro plugin. Kudos to Jaydan Urwin for all his hard work. After installing the plugin, I created a /src/utils/sanityHelper.js file to add all the helper functions I need.

So, let's get the navigation. First of all, I created a helper:

export async function getNavigation(navigationName) {
    const query = `*[_type == "nav" && id == "${navigationName}" ]`;
    const navigation = await useSanityClient().fetch(query);
    return navigation;
}
Enter fullscreen mode Exit fullscreen mode

It fetches all the posts from the nav post type and the passed navigation id.

Next, in my header component I'm doing something like this:

---
import { getNavigation } from "../utils/sanityHelper.js";
const navigation = await getNavigation( 'header_menu' );
---
<ul class="font-bold font-palmiak-font tracking-widest">
{navigation[0].navItems.map((item) => (
    <MenuHeaderMobile href={item.navItemUrl.linkUrl}>{item.text}</MenuHeaderMobile>
))}
</ul>
Enter fullscreen mode Exit fullscreen mode

... and that's it :)

Fetching posts is similar. There are some gotchas.

Images

In the helper file, you'll find the urlForImage function. To use, you have to use:

{urlForImage(post.mainImage).width(640).auto("format")}
Enter fullscreen mode Exit fullscreen mode

Also, check the sanity/image-url documentation. You'll learn more about all its possibilities.

Markdown fields

Astro, by default, doesn't have any method to show markdown data that was fetched from an API. To fix this, we have you use the marked package. This is how I displayed post content:

---
import { marked } from 'marked';
const { post } = Astro.props as Props;
---
<div set:html={marked.parse(post.body)} />
Enter fullscreen mode Exit fullscreen mode

Querying references

When I wanted to display category names in every post, I hit a small bump on the road. Luckly it was easy to solve.

This is what my initial query looked like:

*[_type == "post" ] {
    _id, 
    title, 
    publishedAt, 
    categories,
    mainImage, 
    excerpt,
    slug
} | order(publishedAt desc)
Enter fullscreen mode Exit fullscreen mode

to get all the data related to each category, I had to add []->

*[_type == "post" ] {
    _id, 
    title, 
    publishedAt, 
    categories[]->,
    mainImage, 
    excerpt,
    slug
} | order(publishedAt desc)
Enter fullscreen mode Exit fullscreen mode

Check out this page for more information.

That's it

I hope you'll also find Sanity.io as friendly and easy to use as me. Of course, this article just scratches the surface of what Sanity.io can do and how we can configure it.

Don't forget to share what you have done using Sanity.io.

💖 💪 🙅 🚩
palmiak
Maciek Palmowski

Posted on December 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Playing around with Sanity.io
sanity Playing around with Sanity.io

December 15, 2022