The API design-first approach is relatively new, so there are very few use cases that could help a Product team to implement it. Here’s how the Visma Nmbrs’ product team moved from code-first to API design-first.
Visma Nmbrs is a payroll software provider, so we have to cater for clients’ multiple software integrations. For example, a supermarket employee works shifts and registers their hours worked in planning software. Those hours must be sent to payroll software to calculate the salary and taxes and effectuate the payment. This communication happens through APIs.
Why our API code first approach needed to change
Previously, we had an extensive SOAP API. It had a lot of functional coverage but was built on individual customers’ requests. For every new customer request, we built a new API call, which created a lot of calls that were barely used. It was hard to maintain and made using our API very hard for new partners who wanted to integrate with our software.
When prioritising business value, Visma Nmbrs takes three important stakeholders into account:
- Customers use the Visma Nmbrs UI. They are accountants or companies that need to process their payroll and use the software services offered by our partners.
- Partners are companies that connect their software to the Visma Nmbrs marketplace via APIs.
- Consumers are the partners’ developers using the APIs.
The APIs served as a connection layer but did not solve consumers’ main problems or take their pains into account.
When we started thinking of our APIs as products, we started collecting the workarounds partners used to get what they needed and what took them the most time. We listened to their needs to begin solving their problems.
Why we used the API design-first approach
The API as a product concept matches the API design-first approach very well. The design-first approach enables APIs to take consumers’ feedback into account from the beginning. Unlike a code-first approach, we spend more time on design to ensure fewer corrections when writing code. It increases the chances of building the right APIs for consumers and enforces continuous discovery and delivery.
This matches very well with product management principles. We used it because of this alignment and because it enabled us to ensure we’re continuously creating value for our stakeholders.
When we first began implementing it, there were a few things I didn’t know:
- How would we optimise the product owner and development team roles to the new approach and ensure that everyone involved could be enabled in a way that was efficient for them? This needed to allow every team member to focus on their work while also saving them time.
- How would we integrate the code?
To answer these questions, we needed to iterate until we found an implementation that worked for us.
How we implemented the API design-first approach
Initially, we used the development of a new REST API as an opportunity to mix the code-first and design-first approaches. As the product owner, I did the design process separately from the development team. I mapped out the different integration use cases to understand our partners’ main challenges when integrating with our software. I prototyped the new potential endpoints via OpenAPI specs in Stoplight and validated them with the customer before starting development.
The developers took those specs to code the backend and generated the OpenAPI specification. The goal was for the specs generated from the backend code to match the specs I had generated. I constantly reviewed and improved the descriptions to offer the most intuitive API to consumers. The problem with this initial approach was that, for every new change I made, the developers had to manually make changes on the backend to match.
Because this process was laborious, frustrating and error-prone for us all, we made two significant changes:
- We used the OpenAPI Generator to shift from code-generated to design-generated specifications. This eliminated all the back-and-forth and enabled us to unlock the potential of the design-first approach.
- Instead of requesting every change manually, I took complete control of the specification. As a result, the developers could fully focus on the logic necessary to make the API requests work instead of wasting valuable time on minor changes.
Uncoupling the specs from the backend allowed us to properly document examples for consumers. This made understanding the specs easier for the developers, as they could first see the examples of requests, responses and possibilities. They knew what to expect, enhancing their understanding and making the process more efficient with less back and forth.
In summary, the process when using a mix of both the design-first and code-first approaches looked like this:
After our adaptations, this is what the process looked like:
The most significant difference between these processes was that I could freely make changes to the specification without creating additional work for the developers. I could edit examples and descriptions, add fields or modifications, and create a pull request (PR) for the developers to review. From there, they would pick the part that was relevant to them. The “Generate backend code based on specs” step allowed us to create the best possible product for our consumers.
What we learned from implementing a design-first approach for APIs
When adapting this process to our needs, we had three key insights.
Adaptations will always be necessary
The server-side code generation will not fit out of the box, and adaptations are needed. For example, for every new endpoint we developed, there were strict security measures that we needed to apply. We did this by invoking a general method available for all teams.
To enable that for all our endpoints, we adapted the template from the code generation tool. This was automatically included in the backend code, reducing the manual development steps. You can read all the technical details on OpenApi’s Using Templates documentation.
The development team has to accept the new process and be willing to experiment with it
This was an initiative that came from Product, but it only became possible after the development team understood its advantages. It involved a shift in the way of working between the Product and Development teams. Everyone involved had to be interested in making the changes and improvements.
In my experience, it was very smooth _because _the developers bought into it quickly and were motivated to make it work. Afterwards, we were all proud of the result.
The design approach will fail if you don’t involve your customers
If a team uses the design-first approach without involving the consumers by asking for feedback and keeping them in the loop as much as possible, the result will be an API embedded with assumptions and opinions. This can go wrong and create a lot of frustration.
In our case, the design-first approach was an enabler that allowed us to apply product management best practices and offer the right solution for our partners.
Good product practices the API design-first approach enables
Quicker and easier prototyping
The goal of prototyping is to validate if a solution is suitable for its users or not. The API design-first approach allowed us to validate if the API will solve a consumer’s problem without writing a single line of code. This saved our team effort and development time, as we avoided rebuilding after delivery. Most importantly, it led to a solution more likely to delight API consumers.
Involving consumers early on
Great products are built by involving consumers as early as possible for feedback. I believe in co-creating products with consumers: To solve their needs, they should be actively involved in creating what we build. With the code-first approach it’s possible to include users early on, but it’s easy to focus on the development only at the expense of the consumer perspective.
We were able to involve our customers deeply using the design-first approach. This enabled a much more reliable output by maximising the value we created and minimising the risk of having to rebuild parts of the API.
Specifically, we created an Early Adopter Program in which we selected partners that fit the initial use case and invited them to collaborate with us. Consumers would have direct access to our internal development team via Slack, which created a direct line of communication and a safe environment for the partner’s developers to share their thoughts.
Involving users deeply meant spending more time on discovery, which was worth it because we could deliver a better product to our partners and meet their needs.
Less frustration for developers and product owners
A design-first approach means less effort on development to make changes happen, as special attention is given to descriptions, examples and required fields. With the design-first approach, we could guarantee proper documentation within the API itself to help the developers understand the descriptions more easily and make the best choices.
It’s also possible to achieve good documentation with code-first, but it’s much more laborious as everything has to be maintained on the backend.
Consistency is essential for any product. A product’s features must make sense throughout, and design consistency is expected. The same applies to APIs. The design-first approach makes it easier to pay attention to variable naming, for example, and ensure that it’s thoroughly consistent within one API or multiple APIs. It’s easy to get distracted and use different naming when APIs grow within an organisation.
For example, in the old Nmbrs’s SOAP API, the terms companyId, companyID, CompanyID, and CompanyId would appear in different calls. Consumers had to work around this inconsistency on the backend code while the companyId field was the same. The partner development team had to manually match the API specification, generate a code-based specification, compare both to see if there were errors and continuously re-do this process. I heard complaints of developers taking hours to figure out that this was the problem with the implementation. With design-first, we haven’t had these complaints.
Gabriela is an API Product Manager at Bloomreach. She’s passionate about the problem more so than the solution, and is always focused on generating value for her product’s users. She’s excited about keeping up-to-date with what’s going on in the Product and API industries and does so by reading many books and connecting to the community. Her other big loves in life are dogs, summertime, roadtripping and volleyball.