API Contract: why you are probably automating the process incorrectly

Felipe Solana
adidoescode
Published in
7 min readSep 23, 2022
An antigue typewriter with a blank sheet of paper
Photo by Florian Klauer on Unsplash

API Contract First

An API Contract is a document that explains how your API works and how it should be used. This document is done with the intervention of all the Stakeholders and becomes the single source of truth for the API. Any change in the document can provoke a breach of contract and generate the obligation for the consumers to change their code or to stop working. API Contract First means that all the participants have to reach an agreement before doing any changes in the API, that includes the first version of the API. In any case the API Contract will be created or changed before writing any single line of code, it is the opposite of Code First.

Writing a good API contract is not easy, it requires a lot of effort and time to design it, and I apologize because this article is not going to help you design yours better.

Now I want to talk about the automatization from your API Contract to your code.

Comparing styles

If we think in API probably the first idea that comes to our mind is a REST API, then we think in Open API and the great tool that we have probably used a lot of times, Swagger. We can create beautiful documentation only with annotations in our code and this is great, but… If you have been in this business for some time you have probably lived the times when everything was SOAP, which was very popular sometime ago, yet today a little less.

I remember pretty well when in my first years as a Junior Engineer in a big company, I attended a course in the mythical Sun Microsystems and how fascinated that company was to me. The professor taught us how to create a SOAP server from scratch, starting with the creation of a WSDL, generating the server, generating the client, adding the code, etc. Everything that person wrote was with vi, but that is definitely a topic for another article. The important thing is that in the past we created our RPC APIs doing the contract first. Then we used the tooling to generate our servers and clients, and finally updating them.

Nowadays the same thing happens: we have gRPC where we first define our protobuf file, or we have GraphQL (more of the same). Then we have Open API. It is easy to understand that the same thing has to happen, in the same order from specification to code and not the other way around. Most of the Software Engineers feel comfortable with the idea of annotating the code and then generating the contract. By doing that, your server will be always updated with the last version of the contract, but that only means that they have the power to breach the contract every time and tell the consumer that you are not following the specifications.

Then the only different between methods to develop API today is that in Open API we decided not to do API Contract First.

Something to tell you

To all those Engineers that sometimes think that I prefer to use an autogenerated contract because it is like writing code: the language to define REST API is Open API, a language that all the Stakeholders can understand and use.

There are a lot of tools to do easily design API like Swagger Hub, Apiary, Postman… This aforementioned tools allow us different features like:

  • Collaboration
  • Versioning
  • Immutability
  • Mocking
  • Code generation
  • Creating a style guide
  • Applying API Governance

Using the tools in the correct way is the path to create better and trustable APIs for our consumers while avoiding contract breaching continuously. It is done by putting more emphasis on collaboration, immutability and versioning of our API Contract.

Then.. how is it done?

As you could guess for the previous lines I am against the automatization that happens from the code to the tools like Swagger Hub. Being witness on how Engineers have tried to update the specification in Swagger Hub directly from their pipelines, I want to show you the way that I think the automatization has to happen, which is directly in the opposite direction, from API contract to code. Then you can directly add it to your pipelines to autogenerate the ticket that you will need to make the changes in your code, or even in some situations deploy directly in prod. Disclaimer: the next paragraph is not about how to do a pipeline for that, it is an example that can be used in different ways.

The automatization has to be always from API contract to code.

Automatization example

The starting code can be found here. It is a maven monorepo that contains an example inventory API with the service code written in Java. It consists in an exercise to apply clean architecture ideas and API Contract First.

We begin at the point where we have an application, we have also met with our Stakeholders so we have a new Contract version with changes. Then we have to generate our code.

The new version is already published in our Swagger Hub, we have created the mock then the consumer can start to adapt the new contract in its develop branch. We have included a deprecated property so it is necessary to warn to our consumers when it will be expected to be totally removed. But we will maintain the new version compatible with the previous one until that happens.

The project is divided in layers that make the integration with a different delivery mechanism easier. We could choose gRPC, Kafka, GraqhQL in the future, keeping the same core and only changing one delivery layer for another. In this case we choose a REST API and we have two implementations: Spring Boot and Micronaut, it will be interesting to put both implementations in our Kubernetes cluster and see how they fight each other, and which one will survive.

I did that division with the conviction that it could not be the adequate technology for our application and we might need to change to another with better performance.

Ignore the other folder from the repo and put our attention in application/api

The new Contract is in the contract folder with the 1.0.1 version. We will use swagger-codegen-cli to generate the new interfaces and the new models that we will integrate with our server code. Swagger codegen cli is an external tool, we will download the necessary jar executing the following command:

wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.34/swagger-codegen-cli-3.0.34.jar

Please, copy the download jar to folder Tools.

The configuration that we will use is here: tools/openAPIAutoGenConfing/springBootConfigGenerator.json

{
"invokerPackage":"com.adidas.apiteam",
"groupId":"com.adidas.apiteam",
"artifactId":"inventory-spring-boot",
"modelPackage":"com.adidas.apiteam.springboot.model",
"apiPackage":"com.adidas.apiteam.springboot.api",
"dateLibrary":"java11",
"java11":"true",
"interfaceOnly":"true"
}

There is a .swagger-codegen-ignore in the springboot folder to avoid overriding the pom.xml and the README.md

Now execute the command to create the new the interfaces and new the models. Go to folder application/api, where you can find a README with more information about the process, and execute the following command:

java -jar tools/swagger-codegen-cli-3.0.34.jar generate -i contract/adidas-APIContractFirst-Inventory-1.0.1-swagger.yaml -c tools/openAPIAutoGenConfig/springBootConfigGenerator.json -l spring -o springboot

We can see the output and the generated files below:

INFO  i.s.c.v.g.java.SpringCodegen - Set base package to invoker package (com.adidas.apiteam)INFO  i.s.codegen.v3.AbstractGenerator - writing file /inventory/application/api/springboot/src/main/java/com/adidas/apiteam/springboot/model/InventoryItem.javaINFO  i.s.codegen.v3.AbstractGenerator - writing file /application/api/springboot/src/main/java/com/adidas/apiteam/springboot/model/Manufacturer.javaINFO  i.s.codegen.v3.AbstractGenerator - writing file /inventory/application/api/springboot/src/main/java/com/adidas/apiteam/springboot/model/Stock.javaINFO  i.s.codegen.v3.AbstractGenerator - writing file /inventory/application/api/springboot/src/main/java/com/adidas/apiteam/springboot/api/InventoryApi.javaINFO  i.s.codegen.v3.DefaultGenerator - Skipped generation of /inventory/application/api/springboot/pom.xml due to rule in .swagger-codegen-ignoreINFO  i.s.codegen.v3.DefaultGenerator - Skipped generation of /inventory/application/api/springboot/README.md due to rule in .swagger-codegen-ignoreINFO  i.s.codegen.v3.AbstractGenerator - writing file /inventory/application/api/springboot/.swagger-codegen/VERSION

If we compile now the main project we will see that nothing is broken. It only adds new things, the service works the same as version 1.0.0

Now it is moment to code the feature design for the new contract version.

If you are lucky and have Swagger Hub you can do the same with only a button. You can integrate your repo in Swagger Hub, by pressing a button you will have a new branch with the new interface and model ready to start coding. Then when the designer decides that the new contract is ready to be developed, they can easily press that button and a new version will be created in the repo, and a task can be executed in the pipeline to create a new Jira in the backlog.

Conclusion

We see how we can follow a API lifecycle that starts with the design and automatically creates the necessary code to develop the new feature. No more developers deciding about how the Contract is: this is previously decided by the Designers and the Stakeholders. It doesn’t matter if you have only one consumer or more, design first is the best strategy and offers a lot of advantages with a lot of tools specifically done for helping with that task.

Be happy and API First.

Links

API First:

https://adidas.gitbook.io/api-guidelines/rest-api-guidelines/guides/complete-api-development

https://swagger.io/resources/articles/adopting-an-api-first-approach/

https://smartbear.com/blog/embracing-an-api-design-first-approach/

Clean Architecture:

https://github.com/mattia-battiston/clean-architecture-example

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

https://herbertograca.com/2017/09/28/clean-architecture-standing-on-the-shoulders-of-giants/

Frameworks:

https://spring.io/projects/spring-boot

https://micronaut.io/

The views, thoughts, and opinions expressed in the text belong solely to the author, and do not represent the opinion, strategy or goals of the author’s employer, organization, committee or any other group or individual.

--

--