Spotting mismatches between your spec and your REST-API with hikaku

No Comments

If you provide a REST-API and you create it contract-first, you either use an approach that involves code generation or you have to find another way to make sure that your specification and your implementation don’t diverge over time. In this article, I want to show you how hikaku can help you to ensure that with just a few lines of code.

Contract-first without code generation

All the existing frameworks for writing REST APIs are pretty easy to handle, and they all claim that creating an endpoint is straightforward. So why exactly do we use code generation if we decided to go contract-first? – Because this way, we can guarantee that our specification and our implementation don’t diverge, and everything we change in the specification will be changed in the code automatically. However, I don’t always see a real benefit in this approach.
For small changes or new endpoints that could’ve been written manually very quickly, we have to add new frameworks and dependencies to our project. We basically couple our specification to our implementation with that. We might struggle with the process, which gets more complex, even messy sometimes. The generated code might be ugly, but we say to ourselves that it’s generated, and we should not worry about it. Or we go even further and customize the generated code. Do we really have to pollute our project with all that stuff?

But how to test it?

In case there is no code generation involved, we need another way to make sure that the structural equality for our specification and our code is given. So when I came across this problem, I didn’t want to create test requests which verify the behaviour and implicitly test the underlying structure as well. I wanted a unit test which I can tell that there is a specification of type X and that my implementation is done using framework Y. – Then the test is smart enough to do a comparison on its own.

This is where hikaku, a library crafted for such use cases, comes in. It is written in Kotlin, but of course it can be used for other languages on the JVM like Java as well. Separated into a core module and one module for each converter, it’s designed to support various frameworks.

Sample service

Alright, enough talking, let’s see some code. In this sample project, we’ve got an OpenAPI 3 file as our specification.

For the implementation we are using Spring.

Create a test

The whole project is available on GitHub.
First, we add the dependencies required for hikaku to our build.gradle.kts:

Now we create a JUnit test class in which we start the Spring context and inject it into our test class.

Within the test, we create an instance of the OpenApiConverter and pass the location to our openapi.yaml. For our implementation, we are going to use the SpringConverter and pass the injected ApplicationContext. Both EndpointConverters are added to a new instance of the Hikaku class.
Note that Spring provides /error endpoints, and we want to omit those in our test. The library provides a way to accomplish this. Just add a HikakuConfig containing a list of ignored paths.
Finally, we call the match function on the Hikaku class. And that’s it.

Test results

What about the results? A MatchResult is passed to registered Reporters. The default simply prints the result on System.out. Additional reporters can be created and registered.

In case our service is in sync with its specification the default reporter has the following output:

service is in sync with its specification

Otherwise the test will fail, and we get a list of endpoints which were expected, but not found and a list of endpoints that were found, but not expected.

expected and unexpected endpoints

Go ahead and clone the sample project on GitHub and play with it. I would love to hear how you create your REST-APIs, and if you think this library would be beneficial for your project.

Jannes Heinrich

Jannes works as a software engineer and IT consultant at codecentric. His focus is on the Java environment. He is always interested in new technologies and frameworks and in using them in projects in a meaningful and profitable way.

Comment

Your email address will not be published. Required fields are marked *