Troubleshooting a POST GROQ request using JS Client in Next.js

7 replies
Last updated: May 16, 2021
Hey,
Any pointers on how to send a POST GROQ request using the JS Client? My query is too big…
AI Update

Good news! The Sanity HTTP API does support POST requests for GROQ queries, which is exactly what you need when your query is too long for a GET request.

According to the Query API documentation, there's a specific endpoint for this:

Using POST for Large Queries

POST https://{projectId}.api.sanity.io/v{apiVersion}/data/query/{dataset}

The documentation notes that GET queries have an 11 KB limit due to browser URL length restrictions. When your query exceeds this, you need to use POST.

With the JS Client

Unfortunately, the @sanity/client doesn't have a built-in option to force POST requests. The client uses GET by default for cacheability. However, you have two good options:

Option 1: Use GROQ Parameters (Recommended first step)

Move large parts of your query into parameters to reduce the URL length:

import {createClient} from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  apiVersion: '2025-02-19',
})

const result = await client.fetch(
  `*[_type == $type && category in $categories]`,
  {
    type: 'post',
    categories: ['tech', 'design', 'development'] // Large arrays go here
  }
)

GROQ parameters move data out of the URL and into the request body, which can significantly reduce your query string length.

Option 2: Direct HTTP POST Request

If parameters don't solve it, make a direct POST request to the HTTP API:

const query = `your very long GROQ query here`
const params = {} // optional parameters

const response = await fetch(
  `https://${projectId}.api.sanity.io/v2025-02-19/data/query/${dataset}`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      // Add if you need authentication:
      // 'Authorization': `Bearer ${token}`
    },
    body: JSON.stringify({
      query: query,
      params: params
    })
  }
)

const {result} = await response.json()

The POST endpoint supports the same query options as GET and will also be cached on the CDN, so you don't lose performance benefits.

I’m just getting this error from Next: FetchError: invalid json response body at https://sanity.io/v2021-03-25/data/query/production?query <bigquery>
Really struggling with this 😞
Would you be willing to post your query in its context in Next—including a query that's formed like yours? (The specifics of the query can be changed but it would help diagnose the problem to see something like what you're sending.)
You may also want to curl your query to make sure the error is with the query itself and not your code.
{
      "pageData": 
      *[_type == "policy" && slug.current == $slug] 
      
      {..., 
          pageTemplate{
              ...,
              mainButton{
                  buttonText,
                  "slug": internalLink->{slug},
                  "externalLink": externalLink{...},
              },
              secondButton{
                  buttonText,
                  "slug": internalLink->{slug},
                  "externalLink": externalLink{...},
              },
              introText[]{
                  ...,
                  markDefs[]{
                  ...,
                  _type == "internalLink" => {
                          "slug" : @->slug.current,
                      "type" : @->_type
                      }
                  },
              }, 
          },
          
      content[]{
          ...,
          
      "image":image{
          ...,
          alt, 
          caption,
          ...asset->
      }
  ,
          _type == 'accordionSection' => {
              ...,
              accordions[]{
                  ...,
                  ...@->{...},
                  _type == "manualRef" => {
                      "body": body[]{
                      ...,
                      markDefs[]{
                      ...,
                      _type == "internalLink" => {
                              ...,
                              "slug" : @->{
                                  defined(postFields) => {
                                      "current":postFields.slug.current,
                                  },
                                  defined(slug) => {
                                      "current":slug.current
                                  }
                              },
                              "type" : @->_type
                          }
                      },
                  },
                  }
              },
          }, 
          _type == 'shortcutSection' => {
              ...,
              
      "image":image{
          ...,
          alt, 
          caption,
          ...asset->
      }
  , 
              bgColor,
              shortcuts[]{ 
                  ...,               
                  ...@->
              }
          },
          
  _type == 'feedSection' => {
      ...,
      feedContent[]{
          ...,
          route->{...},
          
      "image":image{
          ...,
          alt, 
          caption,
          ...asset->
      }
  
      }
  },
          
   _type == 'sliderSection' => {
       ...,
      route->{...},
      sliderContent[]->{
          ...
          
      }, 
  },
          
  _type == 'peopleSection' => {
      title,
      people[]->{...}, 
  },
          
  _type == 'registrationFormSection' => {
      ...,
      description[]{
         ...,
         markDefs[]{
          ...,
          _type == "internalLink" => {
                  ...,
                  "slug" : @->{
                      defined(postFields) => {
                          "current":postFields.slug.current,
                      },
                      defined(slug) => {
                          "current":slug.current
                      }
                  },
                  "type" : @->_type
              }
          },
      }, 
      
      "image":image{
          ...,
          alt, 
          caption,
          ...asset->
      }
  
  }
  ,
  
          
          text[]{
              ...,
              
      "image":image{
          ...,
          alt, 
          caption,
          ...asset->
      }
  ,  
              accordions[]{
                  ...,
                  ...@->{...},
                  body[]{
                      ...,
                      markDefs[]{
                      ...,
                      _type == "internalLink" => {
                              ...,
                              "slug" : @->{
                                  defined(postFields) => {
                                      "current":postFields.slug.current,
                                  },
                                  defined(slug) => {
                                      "current":slug.current
                                  }
                              },
                              "type" : @->_type
                          }
                      },
                  },
              },
              shortcuts[]{ 
                  ...,      
                  ...@->{
                      ...,
                      internalLink{
                          "slug" : @->{
                              defined(postFields) => {
                                  "current":postFields.slug.current,
                              },
                              defined(slug) => {
                                  "current":slug.current
                              }
                          },
                          "type" : @->_type
                      }
                  }
              },
              markDefs[]{
                  ...,
                  _type == "internalLink" => {
                          "slug" : @->{
                              defined(postFields) => {
                                  "current":postFields.slug.current,
                              },
                              defined(slug) => {
                                  "current":slug.current
                              }
                          },
                          "type" : @->_type
                      }
              },
          },
          images[]{
              ...,
              ...asset->
          }, 
          route->{
              slug, 
              _type, 
              title,
              ...postFields
              }, 
          manualNews[]->{
              _type, _id,
              postFields{
                  title, blurb, mainImage, slug
              }
          }, 
          newsCategory->{title, _id},      
          people[]->{
              name, _id, photo, role, contactInfo, slug
          },                       
      }
            
      }
  ,
      
       "siteConfig" : *[_type == "siteConfig"] {
        
      ..., 
      logo,
      mainNavigation[]->{slug, page->{"title": title}},
      dropdownNavigation[]->{slug, page->{"title": title}},
      footerNavigation[]->{slug, page->{"title": title}}
  ,
        "contactInfo": *[_type == "mainContact"] {
           ...contactInfo
         },
        "social": *[_type=='social'],
      }
  
    }
The error is still Unexpected Token < in JSON at position 0. Which seems to be Sanity 400 bad request page:
Trying to post the actual get URL that shows up in my terminal but Slack wont let me lol
Whelp. I think the whole problem was using next-sanity that defaults to picosanity.

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?