Index
Edit

Queries

GROQ-queries

The query API is located on https://<projectId>.api.sanity.io/v1/data/query/<dataset>. You can find more information about API URLs and how to find your project id here

The GET form

The basic query api endpoint is very simple:

GET /data/query/<dataset>?query=<GROQ-query>

GROQ-queries may also use parameters. In the query these will be prefixed by a dollar sign and could look something like this: $language. These are submitted as normal url-params:

GET /data/query/<dataset>?query=<GROQ-query>&$language="es"

Because GROQ needs to know the type of the query param clearly, you need to enclose string values in quotes, while numbers and booleans are written in the normal manner:

GET /data/query/<dataset>?query=<GROQ-query>&$string="es"&$bool=true&$number=12.8

A nice feature of GROQ/Sanity is that you can submit very large queries composing a lot of separate queries as one. This is especially powerful when going through the API CDN, since the entire composite is cached as one which can make for very very fast frontends indeed. But of course there is a limit: Because of limitations in some browsers we've put the max limit on GET queries at 11kb. If your URL is longer than that, you will have to submit the query as a POST (see below) foregoing any caching.

Result (queries)

{
  "ms": <server-side processing time>,
  "query": <submitted query>,
  "result": <query result>
}

Caveat: It is a common mistake to assume that the result is an array of documents, but it isn't. It can be any valid JSON value. If the query is *[_id=="myId"][0], the result is the document object unwrapped, for count(*[_type == 'actor' && name match 'weaver']) the result will be a number. If the query is *[_type == 'actor'].name, the result is an array of strings (given that the names are strings).

"Not found" considered harmless

When a document is not found, GROQ still evaluates to a value, thus you don't get 404-errors through this endpoint. Some examples:

  • *[_id == "missing"] results in []
  • count(*[_type == "typoType"]) results in 0
  • *[_id == "missing"][0] results in null
  • *[_id == "missing"][0].someProp also results in null

Syntax errors

{
  "error": {
    "query": "*[",
    "description": "Expected ']' following expression",
    "start": 1,
    "end": 2,
    "type": "queryParseError"
  }
}

The start/end-values corresponds to character-positions in the submitted query and could be used to provide visual feedback as to where the error occurred. description is a human-readable description of the error which may be revised and improved over time an thus should not be used for machine processing, while type is a machine-readable symbol that is intended to be part of the stable api.

The POST form

Queries longer than 11kB can't be submitted using the GET-method (which otherwise should always be the preferred way), so must be POSTed. This endpoint is not supported by the API CDN.

POST /data/query/<dataset>

The payload is a JSON-document like this:

{
  "query": "<the GROQ query>",
  
  // The params-part is optional:
  "params": {
    "language": "es" // you don't use the $-prefixes when submitting as json
  }
}

The results of this endpoint is the same as its corresponding GET form described above.

The DOC endpoint

This endpoint cuts through any caching/indexing middleware that may involve delayed processing. It is designed for use cases where you want to be very sure to get the absolute latest possible version of a document as it is known to the backend. It can only fetch documents by id (i.e. no GROQ) and it is less scalable/performant than the other query-mechanisms, so should be used sparingly.

GET /data/doc/<dataset>/<document id>

Result (DOC)

{
  "documents": [<array of documents with all attributes>]
}

Previous: AuthenticationNext: Listening