How to use GROQ queries with filters in Sanity HTTP API fetch requests?

4 replies
Last updated: Jun 15, 2022
Hi guys. How would I fetch data without sanity client with queries and filter? I know that this works const query = `*[_type=="tweet"]`; const url = `https://<projectId>.
api.sanity.io/v1/data/query/development?query=${query} `; const tweets = await fetch(url).then(res => res.json());

but how would I use this query with filtering
const currentUserTweetsQuery =
*[_type == "tweet" && userId == '${userId}] | order(_createdAt desc)
? (this works via sanity online and via sanity client fetch)into const url = `https://<projectId>.
api.sanity.io/v1/data/query/development?query=${currentUserTweetsQuery} `;const tweets = await fetch(url).then(res => res.json());

Thanks in advance for the help! New to sanity.
AI Update

You're on the right track! The issue is that when you use the HTTP API directly with fetch, you need to properly URL encode your GROQ query, especially the && operator and any quotes. Here's how to fix your query:

// Your GROQ query
const currentUserTweetsQuery = `*[_type == "tweet" && userId == '${userId}'] | order(_createdAt desc)`;

// URL encode it before adding to the URL
const encodedQuery = encodeURIComponent(currentUserTweetsQuery);

const url = `https://<projectId>.api.sanity.io/v1/data/query/development?query=${encodedQuery}`;
const tweets = await fetch(url).then(res => res.json());

The key here is using encodeURIComponent() which will properly encode special characters like:

  • && becomes %26%26
  • Spaces become %20
  • Quotes and brackets get encoded too

However, there's a better approach: Use GROQ parameters instead of string interpolation. This is safer and cleaner:

// Define query with parameter
const query = `*[_type == "tweet" && userId == $userId] | order(_createdAt desc)`;

// URL encode the query
const encodedQuery = encodeURIComponent(query);

// Add the parameter as a separate URL parameter
const url = `https://<projectId>.api.sanity.io/v1/data/query/development?query=${encodedQuery}&$userId="${userId}"`;
const tweets = await fetch(url).then(res => res.json());

Even better: Consider using the @sanity/client library instead of raw fetch. It handles all the encoding automatically and is much cleaner:

import {createClient} from '@sanity/client'

const client = createClient({
  projectId: '<projectId>',
  dataset: 'development',
  apiVersion: '2024-01-01',
  useCdn: false
})

const tweets = await client.fetch(
  `*[_type == "tweet" && userId == $userId] | order(_createdAt desc)`,
  { userId: userId }
)

The client approach is recommended because it automatically handles URL encoding, parameter escaping, and prevents potential GROQ injection issues that can occur with string interpolation. As noted in the GROQ Parameters documentation, using parameters with $ syntax makes queries safer and more maintainable than string concatenation.

Show original thread
4 replies
You’d use a parameter in your query instead of inlining a value. And then you’d pass that parameter as a URL parameter.
const query = `*[ _type == "tweet" && userId == $userId ]`
const url = `https://…?query=${query}&userId=${userId}`
Don‘t forget to run both the query and every paremeter through
encodeURIComponent
(individually).
I figured it out before but thanks for your reply! I tried what you suggested It didn't, just seeing how many ways it can be done. Yea I got it to work and did wrap my initial query in there and it worked, the query via client and online sanity. For those who are reading, this worked for me, to get the latest data because for some reason sanityClient.fetch doesn't give me the latest data after closing the tab, and coming back fresh data is not there even though it's in the database, in nextjs, unless you reload page.
const baseUrl =
https://${process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}.<http://api.sanity.io/v2022-05-10/data/query/development?query=|api.sanity.io/v2022-05-10/data/query/development?query=>

const userTweetsQuery = encodeURIComponent(
*[_type == "tweet" && userId == '${userId}'] | order(_createdAt desc)
);
fetch(
${baseUrl}${userTweetsQuery}
) .then(res =&gt; res.json())
.then(userTweets =&gt; {
console.log(userTweets)
})
.catch(error =&gt; {console.log(error.message)})

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?