npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@arcteryx/sanity-content

v1.78.1

Published

This package exports methods to fetch content from our Sanity CMS. It is heavily influenced by this article recommended to us from Sanity tech contact. [Type-safe GROQ Queries for Sanity Data with Zod](https://www.simeongriggs.dev/type-safe-groq-queries-f

Downloads

264

Readme

@arcteryx/sanity-content

This package exports methods to fetch content from our Sanity CMS. It is heavily influenced by this article recommended to us from Sanity tech contact. Type-safe GROQ Queries for Sanity Data with Zod.

Usage

import { fetchPage } from @arcteryx/sanity-content
import { createClient } from "@sanity/client";

const sanityClient = createClient({
  projectId: "<project id>",
  dataset: "development",
  useCdn: false, // set to `false` to bypass the edge cache
  apiVersion: '2023-05-03',
})

// The `page` object is type-safe. You can expect page to have the typed attributes defined in `pageSchema` of `fragments/page.ts`.
// For example: `page.region`, `page.breadcrumbs.items`, etc.
const page = await fetchPage(sanityClient, {
  market: "outdoor", // "sale" for outlet
  country: "ca",
  language: "en",
  slug: "help/womens/sizing",
});
`

// If you need to define an `interface` for the type of the `page` object, you can do something like this:
interface Props {
  page: Awaited<ReturnType<typeof fetchPage>>,
}

const MyApp = ({ page }: Props) => {
  const breadcrumbs = page.breadcrumbs?.items; // type-safe
}

Folder Structure

This repo is organized into 2 folders, documents and fragments.

documents

Files in this folder will export "fetch" functions that use a SanityClient object to retrieve documents from the content lake. Their function signature should generally be as follows:

// DocumentTypeParams would be the interface to describe the expected params that should be passed to the client to satisfy the groq query.
function fetchPage (client: SanityClient, params: DocumentTypeParams)

fragments

Files in this folder should be small and concise. They're the building blocks used to compose an entire groq query. In general they correspond to the schema definitions created in the sanity-cms repo, but they don't need to be. For example, a schema could have the firstName and lastName attributes, but our groq fragment could choose to query fullName by having groq concatenate both attributes.

In these files we utilize zod to do two things: Define the output schema for our query, and make that schema type-safe.

These files must export 2 objects:

  1. The schema in the format of <fragmentName>Schema. For example: breadcrumbSchema. This object is the zod definition. And it in itself can be composed of other schema fragments.
  2. The query in the format of <fragmentName>Query. For example: breadcrumbsQuery. This is the partial groq query. And it in itself can be composed of other query fragments.

See breadcrumbs.ts for an example of composition.

Document Fragments

These fragments are used in the fetch functions defined within the documents folder. So they should also export 3 more items:

  1. The filter in the format of <fragement name>Filter. For example pageFilter. This is used in the groq query to filter down or search the specific document.
  2. The params in the format of <FragmentName>Params. For example PageParams. (Note: capital case). This is a type-safe interface that specifies the required params that will be passed to SanityClient to satisfy the groq query.
  3. The queryParams validator function. This is to help ensure the params used in sanityClient.fetch match the schema defined by the interface above. This function should usually always look like this: export const queryParams = (params: <FragmentName>Params) => params;. Then the "fetch" function defined in the documents folder should validate the params like so: sanityClient.fetch(query, queryParams(params)).

See fragments/page.ts and documents/page.ts for an example.

sectionSchema

To accept new types for sections field in sectionSchema, add the new type in baseSectionListSchema and not in the sections field itself. This is so that schemas using baseSectionListSchema like orTab will be able to accept this new section type.

GROQ Methods

Referencing Fields

When constructing a query, you are able to access it directly using the name of the value in a shorthand notation.

export const query = groq`{
  name,
  content
}`;

If you need to conduct a more indepth query or rename the key, you need to wrap in double quotes.

export const query = groq`{
  name,
  "contentArray":content
}`;

Coalesce

There are times when your query may not have any data. This will typically return null for your value. To ensure that you return a value, you can use the coalesce function. This is valuable when creating a schema using an array; if there are no items in the array, return an empty array rather than null.

export const query = groq`{
  name,
  "content": coalesce(content, [])
}`;

Optional Fields

There are times when you want the output of your data from Sanity to include optional fields. An example would be the inclusion of a component in certain scenarios. If the component is to be included in the view, you would add it in sanity and expect that key to be present in the response. If the component is not to be included, than that key will be omitted from the response.

Example:

export const query = groq`{
  name,
  content != null => {
   content
  }
}`;

In this case, if content exists in the query than it will be retreived and returned in the response.

const response = {name:'', content:{...}}

If there is no content in the query, then it will be omitted from the response

const response = {name:'',}

Another option would be to use the coalesce function and return a default value

export const query = groq`{
  name,
  "content" : coalesce(content, {})
}`;

If there is no content in the query, then the fallback will be used. This method will also require a more complicated Zod schema since you will need to account for the nested undefined values.

const response = {name:'', content:{}}

However, this approach will produce a type signature that will contain multiple undefined fields. This may require adapting in the front end.

Zod Methods

Strictly Defined a String

To ensure that a value coming from the Content Lake is strictly equal, you can use the z.literal method.

export const schema = z.object({
	type: z.literal("button"),
});

If this schema is called and the type does not equal "button", the validation will fail.

Type Clarity

When using Zod data types, it helps to distinguish Zod types against Javascript data types when it's used like this:

z.object()
z.array()
z.string()

But not this:

const { object, array, string } = z;

object()
array()
string()

Releases

This repo will automatically publish releases to @arcteryx/sanity-content on npm when there is a merge to main. We utilize the semantic-release package to handle this for us. It also depends on our commit messages following conventional commits.