👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

GROQ Readability Helper 🤓

By Hrithik Prasad & Jono Alford

Less is more - We're breaking down some of the core helpers we use when building our websites

This can help you extend your groq pretty easy 😌


export const refExtend = (
  name: string,
  isArray = false,
  ext: Array<string> = [],
) => groq`
  defined(${name})=>{
    ${name}${isArray ? '[]->' : '->'}{
      ...,
      ${ext.join(',')}
    }
  }
  `;

export const extent = (
  name: string,
  isArray = false,
  ext: Array<string> = [],
) =>
  groq`defined(${name})=>{
    ${name}${isArray ? '[]' : ''}{
      ...,
      ${ext.join(',')}
    }
  }`;


Creating fragments with above functions are neat 😉


export const internal = groq`internal->{${slug}}`;

export const checkBrokenLink = groq`"isBroken":select(
  defined(internal)=>false,
  defined(external)=>false,
  true
),
`;

export const extractLink = groq`"href": select(
  defined(internal)=>internal->slug.current,
  defined(external)=>external,
  null
)`;

export const link = extent('link', false, [internal]);

export const customLink = extent('customLink', false, [
  internal,
  extractLink,
  checkBrokenLink,
]);

export const markDefs = extent('markDefs', true, [customLink]);

export const button = extent('url', false, [
  internal,
  extractLink,
  checkBrokenLink,
]);

export const buttons = extent('buttons', true, [button]);

export const richText = extent('richText', true, [
  markDefs,
  buttons
]);

export const spotLight = refExtend('spotlight', false, []);

export const faqs = refExtend('faqs', true);

export const category = refExtend('categories', true);

export const pageBuilder = extent('pageBuilder', true, [
  richText,
  buttons,
  category,
  faqs,
  videoEmbed,
  link,
]);

export const author = refExtend('author');

This is the end goal making the query more readable and clean 😏


// author , category, richText, 
// pageBuilder, link 
// are fragments for the articles 
export const articleQuery = groq`*[_type == "article" 
   && defined(slug.current) 
   && slug.current == $slug][0]{
    ...,
    ${[
      author, 
      category, 
      richText,
      pageBuilder,
      link
      ].join(',')}
  }`;

Before and After query 👀

// Before Cleaning

const pageQuery = groq`*[_type == "page" 
  && slug.current == $slug][0]{
    ...,
    pageBuilder[]{
      ...,
      buttons[]{
        ...,
        url{
        ...,
        internal->{
          slug 
        } 
      } 
    }, 
    categories->{ title },
    richText[]{
      ...,
      markDefs[]{
        ...,
        customLink{ 
          ...,
          internal->{
            slug 
            
          }
        } 
      } 
    }, 
    link{
      ...,
      internal->{ 
        slug
        } 
    } 
  } 
}`;

// After Cleaning 

export const articleQuery = groq`*[_type == "article"
 && defined(slug.current) 
 && slug.current == $slug][0]{
  ...,
  ${[author, category, richText, pageBuilder, link].join(',')}
}`;

One issue that is often discussed with GROQ is that its syntax can become unwieldy and difficult to manage as queries become more complex, especially when using long and repetitive fragments. This can reduce the code's readability and maintainability, making it difficult for developers to modify and update their queries efficiently. This issue emphasizes the importance of using best practices and effective coding techniques when using GROQ to keep queries manageable and easy to understand even as they become more complex.

Any more questions?

We're always trying to improve knowledge around Sanity, GROQ & Next.js. We've tried to collate a bunch of questions we wanted answers to when we first started working with the composable content cloud. If you have any more questions you'd like answers to, ☎️ Get a meeting booked in or drop us an email at

Contributors

Other schemas by authors

Cursor Prompt

Thinking about getting started with AI? Well we're just going to share our latest and greatest prompt so you don't have to do the hard work

Go to Cursor Prompt

Portable Text Mock Content

If you're looking to mockup portable text in Storybook without a Sanity backend, this is the schema you're looking for

Go to Portable Text Mock Content