Here below is a sample GraphQL query.
{
users {
id
email
}
}
The query above specifies that we want to retrieve all the users in our system and return only the id
and the email
.
Great! π
Now, here is also a query. See below:
[users] { id, email }
Or we could also write it this way,
*[] {
id,
email
}
Alright. Awesome. We call the above as Graph-Relational Object Queries or GROQ for short but what exactly is it?
Before We DiveΒ In
I made a quick demo so we could see it in action. The video is 5 minutes only. If you want to skip the video and read through it, click here.
Or click here to watch the video.
Oooops! Didn't managed to finish my demo there. π
So for the last example, we want to get only results id
, name
, and base
stats. The query would be like this below:
*[ id == 4 ] {
id,
"name": name.english,
base,
}
And here's the result:
[
{
"id": 4,
"name": "Charmander",
"base": {
"HP": 39,
"Attack": 52,
"Defense": 43,
"Sp. Attack": 60,
"Sp. Defense": 50,
"Speed": 65
}
}
]
Getting Started
In today's modern web, GraphQL has pretty much changed how we approach fetching data. For so long, we've gone accustomed to thinking in terms of endpoints. REST API had become the de-facto standard until the former came. One can't simply ignore the benefits of using it but unfortunately, not everyone has the capacity to begin adopting it and/or start new.
NOTE: GraphQL is not a replacement for REST API.
So now, the question is - "Is there a way that we could gain GraphQL's declarative and expressive syntax without doing much work on our good old responses in JSON format?"
Well, the answer to that is, YES!
Absolutely.
Graph-Relational Object Queries (GROQ)
GraphQL is a query language for API's and GROQ is also a query language but JSON-based. It carries on the work that has become so fashionable similar to the implementations of GraphQL which allows robust transformations, filters, projections, and many more.
In simpler terms, GROQ just like GraphQL allows us to describe exactly how we want to shape our data through filters, projections, and many more.
What's great with GROQ is that it also takes it a step further...
Let's go back to our example query above, here shown below:
*[] { id, email }
If you're new, you'd probably reject what you're seeing. When I first started using GROQ, I have this feeling that it's not something I shouldn't get myself into and learn. I was wrong, and I realized how it could be useful in other areas of my professional career as a developer.
*
denotes everything, within the []
is our filter (though not required here but for the sake of example) and lastly, the { id, email }
is our transformation which only returns those fields.
It's not that easy from the very beginning but just like any other thing we try to learn, it gets easier through practice.
Let's Play
Here below are basic to advanced usages of GROQ with its corresponding GraphQL equivalent. The data is based on Pokemon's API.
- Find all Pokemon of Grass-type together with their stats
*["Grass" in type] {
"name": name.english,
base,
}
Play with it here: https://groq.dev/OdzfsmdQ8fobJP8j567UdH
And the GraphQL equivalent below:
{
pokemons(filter: {type: {in: "Grass"}}) {
name: name.english
base {
HP
Attack,
Defense
"Sp. Attack"
"Sp. Defense"
Speed
}
}
}
- Find all Pokemon of Grass-type together with their stats and order results by their speed in descending order.
*["Grass" in type] {
"name": name.english,
base,
} | order(base.Speed desc)
Play with it here: https://groq.dev/nyUE9QKQbTB8vVGYKOrAbk
And the GraphQL equivalent below:
{
pokemons(sort: {fields: base__Speed, order: DESC}, filter: {type: {in: "Grass"}}) {
name: name.english
base {
HP
Attack,
Defense
"Sp. Attack"
"Sp. Defense"
Speed
}
}
}
- Find the total count of Pokemon of type Grass-type.
{
"GrassPokemonsCount": count(*["Grass" in type])
}
Result:
{
"GrassPokemonsCount": 97
}
Play with it here: https://groq.dev/nTm9ARCLuYmDlpLIMTXlIr
Why GraphQL alternative? (Real Life Usage)
In our experience, using GROQ with our REST APIs has allowed us to take its superpowers like filtering, sorting, and shaping our JSON response data however we want it. It has brought tremendous benefits and it never felt so easy. From an investment standpoint, sure, you'll have to learn GROQ's syntax additionally but the benefits are just tenfolds.
For example in one of our eCommerce projects, we fetch the JSON data and used GROQ to do multi-level filtering based on customers' selection.
It's such a breeze of joy.
Let's say, given all shoes, get all of the color blue and the size is greater than 12.
Pretty contrived example below:
import { parse, evaluate } from 'groq-js'
let input = *[type == "shoes" && color == "blue" && size > 12] {
id,
name,
description,
price,
images,
}
// Returns an ESTree-inspired syntax tree
let tree = parse(input)
let dataset = await fetch(PRODUCTS_API_ENDPOINT);
// Evaluate a tree against a dataset
let value = await evaluate(tree, {dataset})
// Gather everything into one JavaScript object
let shoeProducts = await value.get()
GROQ-JS is a (work-in-progress) JavaScript implementation of GROQ which follows the official specification.
And that's it! No need for GraphQL. We've supercharged our REST API without doing too much. π
To learn more about GROQ, head over to Sanity.io introduction, and refer to this cheat sheet anytime. I've also found some challenges you could try like this one here.
Top comments (0)