Easily Create a Star Wars GraphQL API with RESTHeart

Dive into the world of GraphQL and RESTHeart, and may the force be with your data!

Andrea Di Cesare
SoftInstigate Team
4 min readDec 12, 2023

--

Photo by Jonathan Cooper on Unsplash

Hey there! Are you excited about GraphQL and RESTHeart? Well, you’re in for a treat! Today, we’re going to dive into creating a GraphQL API using RESTHeart, inspired by the classic Star Wars characters and episodes just like the GraphQL.org tutorial does. And guess what? You don’t need to write a single line of code!

You’ll find more details about this tutorial on RESTHeart website: https://restheart.org/docs/mongodb-graphql/tutorial

Understand the Basics

  • GraphQL: A query language for your API and a runtime for executing those queries by using a type system you define for your data.
  • RESTHeart: an innovative Open Source framework designed to streamline the development of HTTP microservices. It provides developers with ready-to-use, intuitive APIs, including REST and GraphQL APIs for MongoDB. This framework is crafted to enhance developer efficiency, enabling rapid deployment of robust microservices with minimal setup.

Getting started

First things first, make sure you have RESTHeart v7.6.4 or higher. We’re going to define a JSON configuration, known as GraphQL App Definition, and store it in the special collection /gql-apps.

With RESTHeart, all it takes to bring your GraphQL API to life is simply defining a GraphQL App Definition. That’s right, no complex coding or backend gymnastics needed! Just define, and RESTHeart handles the rest, exposing your fully functional GraphQL API in no time.

Setting Up the Environment

Starting RESTHeart and MongoDB is a breeze with Docker. Just run this one-liner:

$ curl https://raw.githubusercontent.com/SoftInstigate/restheart/master/docker-compose.yml -o docker-compose.yml && docker compose up

If Docker isn’t your thing, check out the setup section in the RESTHeart document for alternative installation methods.

Creating Collections

Our first step in the RESTHeart is to create collections for our Star Wars API. We are going to use the RESTHeart’s REST API for MongoDB.

Star Wars Characters: This is where our character data lives.

$ http -a admin:secret PUT :8080/star-wars-characters

GraphQL App Definitions: This collection holds our API definitions.

$ http -a admin:secret PUT :8080/gql-apps

By the way, we’re using Httpie, a simple and powerful CLI HTTP client.

Populating Data

Now, let’s populate the /star-wars-characters collection with our favorite characters like Luke Skywalker, Darth Vader, and others.

$ echo '[{"_id":1000,"name":"Luke Skywalker","friends":[1002,1003,2000,2001],"appearsIn":[4,5,6],"homePlanet":"Tatooine","heroOf":4},{"_id":1001,"name":"Darth Vader","friends":[1004],"appearsIn":[4,5,6],"homePlanet":"Tatooine","heroOf":5},{"_id":1002,"name":"Han Solo","friends":[1000,1003,2001],"appearsIn":[4,5,6],"homePlanet":"Corellia"},{"_id":1003,"name":"Leia Organa","friends":[1000,1002,2000,2001],"appearsIn":[4,5,6],"homePlanet":"Alderaan"},{"_id":1004,"name":"Wilhuff Tarkin","friends":[1001],"appearsIn":[4],"homePlanet":"Eriadu"},{"_id":2000,"name":"C-3PO","friends":[1000,1002,1003,2001],"appearsIn":[4,5,6],"primaryFunction":"Protocol"},{"_id":2001,"name":"R2-D2","friends":[1000,1002,1003],"appearsIn":[4,5,6],"primaryFunction":"Astromech","heroOf":6},{"_id":3000,"name":"TIE Advanced x1","length":9.2}]' | http -a admin:secret POST :8080/star-wars-characters?wm=upsert

Here’s a snippet of the JSON array we’re using:

[
{"_id":1000,"name":"Luke Skywalker","friends":[1002,1003,2000,2001],"appearsIn":[4,5,6],"homePlanet":"Tatooine","heroOf":4},
....
]

Defining the GraphQL App

Next, we define our GraphQL app:

$ echo '{"_id":"star-wars","descriptor":{"name":"star-wars","description":"GraphQL application used in the Star Wars Tutorial","enabled":true,"uri":"star-wars"},"schema":"union SearchResult = Human | Droid | Starship enum LengthUnit { METER } enum Episode { NEWHOPE EMPIRE JEDI } type Starship { _id: Int! name: String!  length(unit: LengthUnit = METER): Float } interface Character { _id: Int! name: String! friends: [Character]! appearsIn: [Episode]! } type Human implements Character { _id: Int! name: String! friends: [Character]! appearsIn: [Episode]! homePlanet: String! } type Droid implements Character { _id: Int! name: String! friends: [Character]! appearsIn: [Episode]! primaryFunction: String! } type Query { hero(episode: Episode!): Character search(text: String!): [SearchResult] }","mappings":{"Episode":{"NEWHOPE":4,"EMPIRE":5,"JEDI":6},"SearchResult":{"$typeResolver":{"Human":"field-exists(homePlanet)","Droid":"field-exists(primaryFunction)","Starship":"field-exists(length)"}},"Character":{"$typeResolver":{"Human":"field-exists(homePlanet)","Droid":"field-exists(primaryFunction)"}},"Human":{"friends":{"db":"restheart","collection":"star-wars-characters","find":{"_id":{"$in":{"$fk":"friends"}}}}},"Droid":{"friends":{"db":"restheart","collection":"star-wars-characters","find":{"_id":{"$in":{"$fk":"friends"}}}}},"Query":{"hero":{"db":"restheart","collection":"star-wars-characters","find":{"heroOf":{"$arg":"episode"}}},"search":{"db":"restheart","collection":"star-wars-characters","find":{"name":{"$regex":{"$arg":"text"},"$options":"i"}}}}}}' | https POST :8080/gql-apps?wm=upsert

This configuration includes types like Human, Droid, and queries like hero and search.

Playing with the API

Let’s fetch a Hero with the following query:

{
hero(episode: JEDI) {
name
friends {
name
}
… on Droid {
primaryFunction
}
… on Human {
homePlanet
}
}
}

Execute the request with httpie:

$ echo 'hero(episode: JEDI) { name friends { name } … on Droid { primaryFunction } … on Human {homePlanet}}' | http -a admin:secret POST  :8080/graphql/star-wars

{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
],
"primaryFunction": "Astromech"
}
}
}

Now let’s search data with the following query:

{
search(text: "an") {
… on Character {
name
}
… on Starship {
name
length
}
}
}

Execute the request with httpie:

$ echo '{ search(text: "an") { … on Character { name } … on Starship { name length } } }' | http -a admin:secret :8080/graphql-star-wars Content-Type:application/graphql

{
"data": {
"search": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "TIE Advanced x1",
"length": 9.2
}
]
}
}

Understanding the Magic Behind

The beauty of RESTHeart is how it maps GraphQL types to MongoDB data. For instance, the Episode enum is mapped to integers, and the Character interface uses a $typeResolver.

Conclusion

And there you have it! A Star Wars GraphQL API up and running with RESTHeart, with no coding required. Dive into the world of GraphQL and RESTHeart, and may the force be with your data!

--

--