How do you test and debug Scala applications that use GraphQL?
It's very easy to start, and in this article we show you how. We also show the interactions between the application components starting from receiving the GraphQL queries until sending responses to the client application.
By the end of our guide, you'll feel comfortable with testing and debugging GraphQL APIs in Scala.
Before we show the tests, let's first have a look at the Scala project.
Scala, Sangria, and GraphQL API
The application we test and debug is based on Scala 2.12, Play Framework 2.7, and Sangria.
A complete guideline on how to create a GraphQL API server in Scala you can find here.
To write tests, we opted for the default Play's utilities. And since our GraphQL server will send JSON, we'll need to
transform it to valid Scala objects. Hence, we also need to install spray-json
.
Here are all the dependencies we registered in build.sbt
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The repository with the code is located here: GraphQL API example with Tests. Our application uses the built-in mechanism of evolutions in Play Framework that allows us to automate creating and modifying the database schema. Specifically, it is used to add three Post object into the in-memory instance of the H2 database.
Below is the project structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
What do we have in the test/specs
directory? First, let's explain what TestHelper
and PreparedInput
are.
TestHelper
is a trait that imports the basic functionality to be used by all concrete test classes. PreparedInput
is the data — GraphQL queries and mutations — that we'll feed into Play's FakeRequest
for testing. We keep
them in a separate trait to improve the code legibility.
There are also two classes that contain the test cases. GraphiQLRouteSpec
verifies that our AppController
responds
with the GraphiQL HTML template. This will be used for debugging later in
this article. PostSpec
contains the tests for our Post entity.
In the next section, we discuss the TestHelper
trait. After that, we'll focus on how a test is created.
Preparing for testing GraphQL in Scala with TestHelper
Let's create a trait TestHelper
that imports a few key dependencies required for all test classes in our Scala app.
Each concrete test class will extend TestHelper
to avoid duplicating dependencies.
Here are the dependencies that test/specs/TestHelper.scala
imports:
PlaySpec
, a base class for tests for Play Framework applications.GuiceOneAppPerSuite
, a trait that provides a new instance ofApplication
for ScalaTestSuite
.Injecting
, makes possible to inject components under test into test classes.PreparedInput
, a trait that contains the variables with the entry data.
The TestHelper
trait looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Writing a GraphQL test in Scala
Let's now focus on testing the code for the Post entity. For that, we create a class PostSpec
, which extends
TestHelper
. PostSpec
will hold the test cases that verify the successful and unsuccessful scenarios when the query
or mutation is handled by the controller (the AppController
in this case) for the entity Post.
A typical test looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Notice that we first imported models.PostJsonProtocol._
; it contains implicit
that will greatly simplify our work
with queries and mutations and will let us convert the incoming JSON responses from the API server back to Scala objects.
Remember that implicit
is available in app/models/Post.scala
. As for the code that converts JSON to Scala objects,
look for the PostJsonProtocol
implementation in Post.scala
.
The test above verifies that the query is successfully parsed, the correct resolver is called, and resolver returns the correct data.
Here are a few more details how this test was created:
- We specify to which test suite the test refers:
"Post queries" must { /* test */ }
. - We give a name for the test. The name should clearly specify what the test verifies:
"finds a post by ID" in { /* test */}
. - Using the Play's object
FakeRequest
, we imitate sending an HTTP request to our Scala API:
1 2 3 |
|
Pay attention to the variable findPost
. This is JsValue
that contains the GraphQL query or mutation that are sent to
the Scala server. All these variables you can find in the trait PreparedInput
(this file is located next to
PostSpec
and TestHelper
).
- We finally send a request:
1
|
|
Next, we perform a preliminary validation of a string that we received in response. The Scala server may return a JSON
response with two fields — data
and errors
. If errors weren’t produced when a query was
parsed or executed, the errors
field won't be presented in the JSON response.
1 2 |
|
In the response object, we expected at least one instance of the Post entity. We just parse the received response and convert it to a Post object:
1 2 3 |
|
After that, we verify that the Post instance we received has the correct data:
1 2 3 4 |
|
You can find a few more tests in PostSpec.scala
, and all of them are created the same way.
Now, just clone the project and run the tests from the root directory. First, run sbt
, and when you are in the SBT
console, run the tests:
- Run all tests using the
test
command, - Run a separate spec with the command
testOnly *PostSpec
, or - Run a separate test case with the command
testOnly *PostSpec -- -z addPost
.
If the tests are successfully executed (at least, they should), you can see an output similar to the one below in your console:
Basic testing Scala and GraphQL is done. We can focus on how to debug our Scala API.
Debugging a Scala and GraphQL API
You can debug a Scala API using any HTTP client such as Postman, Insomnia, and others. We recommend a popular client Insomnia as it supports testing GraphQL queries and mutations and can show you various errors.
There's also a safe default — the browser IDE GraphiQL. In the official GraphiQL repository, you can find ready-to-use implementations of GraphiQL and use them in your Scala application.
To demonstrate how debugging is done, we use GraphiQL for its simplicity.
In our Scala application, we added the template graphiql.scala.html
under app/views
. To be able to debug with
GraphiQL, our application has a controller method to serve this template:
1
|
|
Also, we added a respective route to conf/routes
:
1 2 |
|
Run the application using the command sbt run
and open your browser at http://localhost:9000
. (If necessary, apply
the script to migrate the in-memory H2 database instance.)
As you can see in the screenshot, the debugger workspace is divided into four areas:
- First goes the field where you can write queries and mutations.
- Second is the field to add and configure variables for queries (optional).
- Third is the area where you see the returned JSON responses from the server.
- Fourth is the tab Docs where you can view the entire GraphQL schema for your API.
Let's have a closer look at Docs (shown in the screenshot below).
You can navigate to a concrete schema query or mutation.
Below is the list of available mutations in our sample Scala app. Notice that the obligatory variables are have the exclamation point "!" after them:
To debug a GraphQL server, you can first verify if your schema looks fine. Do the queries and mutations look right? Are the parameters passed to them correct?
If you're satisfied with how the schema looks, you can start debugging by sending API requests. The request below attempts to add a new post:
1 2 3 4 5 6 7 |
|
In response, a JSON object is returned. Here's what it looks like if the request was built correctly:
1 2 3 4 5 6 7 8 9 |
|
And this is what you get in return from our Scala server if there's an error in a GraphQL query. For example, if you
send an addPos
query instead of addPost
, you get a default error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
If you'd like to know how to handle such errors in a GraphQL and Scala API, you can read a dedicated article on error handling.
As you can see, a default GraphiQL IDE is good enough to debug simple cases. If you want a bit more functionality, try out Insomnia or any other similar tool.
Using the simple tools such as the default GraphiQL IDE and PlaySpec, you can debug and test your GraphQL and Scala API. And if your integration tests are written properly, you'll always be sure that the errors will always expose themselves.