GraphQL APIs with Quarkus

A query language for your API

In this article, I’ll show you Quarkus GraphQL support. As an example, I use the Superheroes application from my previous articles. We will discuss some GraphQL topics.

Code, dependencies and model
The source code for this app is available on Github. If you like, you can try the examples by yourself. As dependencies, I included e.g. SmallRye GraphQL and lombok. Here you can have a detailed look at the pom.xml file.

Quarkus helps you to create GraphQL APIs. The GraphQL schema is going to be generated. You just have to define your model. Here I show you as an example the Superhero data transfer object. I use DTOs to expose data from an API. Lombok @Data takes care of getter, setter, toString, and the equals and hashCode methods.

import lombok.Data;

@Data
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public class Superhero {

    String name;
    City city;

}

Fetching data
To query all cities you just have to send a command like this to the GraphiQL UI http://localhost:8080/q/graphql-ui/:

{
    allCities {
        name
    }
}

And with GraphQL it’s quite easy to fetch object graphs. For example, we could query a city with their superheroes like this.

 query getCity {
     city(cityId: 0) {
         name
         symbol
         superheroes {
             name
         }
     }
 }

Resolver and mutations on the server-side
A resolver is responsible for defining queries. All Queries are located in SuperheroResolver.

@GraphQLApi
public class SuperheroResolver {

	@Inject
	SuperheroService superheroService;

	@Query("allCities")
 	@Description("Get all cities.")
 	public List<City> getAllCities() {
 		return superheroService.getAllCities();
 	}
 ...
}

I have separated the mutations from the queries. Mutations are write operations like create, update or delete. Here I show the create() method from SuperheroMutations with SuperheroInput as an input object.

@GraphQLApi
public class SuperheroMutation {

	@Inject
	SuperheroService superheroService;

	@Mutation
	public Superhero createSuperhero(@Name("superhero") SuperheroInput superheroInput) {
		var superhero = new Superhero(superheroInput.getName(), superheroInput.getCity());
		superheroService.addSuperhero(superhero);
		return superhero;
	}
...
}

Testing GraphQL APIs
It’s pretty cool that Quarkus automatically generates a GraphQL schema based on your source code. To display the schema, just invoke http://localhost:8080/graphql/schema.graphql. Here I want to show you quickly, how to write automated tests. How do we test a GraphQL API? Here comes Rest-Assured to the rescue. You can write tests in a manner as you already know from REST.

@QuarkusTest
public class SuperheroTest {

	@Test
	void allCities() {
		final Response response = given()
				.contentType(ContentType.JSON)
				.body("{\"query\":\"{\\n allCities{\\n name\\n}\\n}\"}")
				.when()
				.post("/graphql")
				.then()
					.assertThat()
					.statusCode(200)
				.and()
					.extract()
					.response();

		final List<City> allCities = response.jsonPath().getList("data.allCities", City.class);
		assertThat(allCities)
				.isNotEmpty()
				.hasSize(2)
				.extracting(City::getName)
				.contains("Gotham City", "New York City");
	}

}


Conclusion
I like the GraphQL support from Quarkus. It’s great that the GraphQL schema is generated automatically through code and annotations. In the next part I’ll show you how to test you GraphQL API with curl, the GraphiQL tool and insomnia.

Photo by Raphaël Biscaldi on Unsplash

Links
https://github.com/claudioaltamura/quarkus-graphql-superheroes
https://quarkus.io/guides/smallrye-graphql
https://rest-assured.io/