It is not an overstatement to say that building core services and exposing its APIs has become the norm in technology world. APIs abstract the functional complexity behind a very simple and easy to use interface. Today, businesses are exposing Infrastructure to Technology to Information to Storage to Anything that you can possibly imagine as a service. This API-zation transformed many businesses and enabled its consumers to innovate in ways which was never so easy before. While it hugely benefited startups to roll up its sleeve by putting few APIs together, enterprises are not left either.
API-zation did not stop with exposing something to external consumers. With Service Oriented Architecture (SOA), even internal components communicate with each other via services. If you have worked in enterprises which have adopted SOA, you will know that there will be 100s of services exposed for internal clients. With the advent of Microservices, number of services could be even more amplified. If you have ever worked as part of Customer Support (CS) product development team, you will be aware that CS app will need to consume almost all of those internal services to provide capabilities for customer support agents. Hence, CS teams are vulnerable to the glitches happening in API world more than any other team within an organization. As a design engineer from CS product development team, we have gone through lot of those and here are few guidelines service owners can follow to help clients like us within an organization.
While exposing a new API
Do not design for a client
A service is a self contained black-box. APIs allows clients to access or modify its state. So the APIs associated with a service, its request and response should center around the capabilities that a particular service provides. Sometimes service owners tend to design APIs as per their understanding of requirements from the initial set of clients. So when a new client is on-boarded, they enhance it based on new requirements and it goes on. This enhancement may also lead to compromises if the new requirement conflicts with the initial design or contract. Over a period, service becomes so complicated and ends up with lack of clarity even among owners. It is absolutely fine to develop and expose APIs only when it is needed for clients, but the service definition, set of APIs and its contract must be well-defined and it should never change for each client.
Take time to lay a proper foundation
I strongly believe that change is inevitable in technology world (in fact any industry for that matter). If a service doesn’t change, it implies it is getting older and stays behind in times. So it should continuously improve over time and some improvements may even require a change in service contract. Also, it is very difficult to have a complete picture when we start designing a service. So changes are fine in initial stages as long as it is not too many. We have seen some teams changing the design and contract almost every two weeks. In cases where we do parallel development, clients are also forced to change too often leading to confusion, rework and wasted effort. Service team should spend enough time on its initial design even if it takes longer than they originally anticipated. It is OK to deliver a proper foundation late rather than giving a half-baked confusion early. Even if we can’t cover every aspect, most of the things should be clear and the first version should be published to clients only after that.
Use HATEOAS (for RESTful services)
I wonder if many service owners are aware of what HATEOAS is. It is a principle of using hyperlinks to navigate through APIs. Let’s say a wallet service is returning list of financial instruments attached to the wallet. To view more details about a particular financial instrument, typically we will construct and send another request using the unique financial instrument identifier returned in the first API’s response. How we construct that request is completely dependent on the service contract, but it is the client’s responsibility to do it. But with HATEOAS, the first API call will return hypertext links for each financial instrument and we can get more details about any financial instrument using it. Here the service is having complete control and client just follows links returned by the service. Clients need not know about detailed contracts. Lot of external APIs are designed with HATEOAS nowadays, but nobody bothers about it when designing APIs for internal clients.
Use proper HTTP methods and return codes (for RESTful services)
Often API statuses are returned as part of the response message with 200 HTTP return code. Also, many service owners only use GET and POST methods and completely ignore the rest. I hate to call these services as RESTful because it is not completely utilizing HTTP design principles and even HTTP clients needs extra code to properly understand the response. Service owners should realize that adopting HTTP principles would lead to spending less time explaining how your API works (differently).
Provide a clear documentation
Providing a thorough and unambiguous documentation is very important for external consumers. It is equally important for internal consumers as well. Even if your client sits in the next cubicle, it is still important to provide a quality document. This will not just serve as a reference for all future clients, it is a reference to the owning team as well. Most of the API integration time is spent on understanding the API and a good documentation will reduce lot of that effort. Please do not underestimate the importance of it.
Avoid domain specific terms
This is another common mistake you can find in internal services. Sometimes teams starts using domain specific names or program names in their interface. These terms are completely meaningless to an outsider and these meaningless words would lead to difficulties in understanding your service. So avoid meaningless terms by all means.
Always consider filtering, sorting, searching and pagination
Providing pagination and mechanisms to search, filter and sort results is a very basic requirement and should not be an afterthought. It is very easy to accommodate such features in design phase rather than after implementation.
Provide a playground and test data
Keep a working stage where your service is running and up-to-date. As I mentioned already, key part of API integration is to gain familiarity it and there is no better way to understand than testing it. Always maintain working stage and some test data for client to play and get familiar with your APIs.
While modifying an existing API
Use Proper Versioning
Changing a published and used interface without updating its version is unacceptable even if the change is backward compatible. Versioning reduces impact to clients and isolates the risk. It also gives enough time for clients to migrate to new version. Versioning is not strictly followed for internal services as much as they do for external services. Important thing to note is that internal APIs undergo far too many changes than external facing APIs and hence versioning is very important for internal APIs as well.
Keep documentation up-to-date
As much as it is important to document APIs, it is equally important to maintain whenever we make changes to it. Any outdated information in a document will doubt its whole credibility and hence its existence. Documentation should included as part of acceptance criteria for any modifications in the API.
Communicate changes to all your clients so that they can plan for upgrading to new version of your API. Also, mention how long you will support the older version in case you are planning to get rid of that old version soon.
While deprecating an API
Provide alternate options
From a client’s perspective, all functionalities built on top of that deprecated API will get impacted if an API is deprecated. So it is very important to provide alternate APIs using which clients can build the same functionality. Quite often, the new API will not support all capabilities or information as in old API and this is problematic for clients. Do not expect clients to find those differences and come back to you. As a service owner, it is your responsibility to clearly inform what you support or don’t support going forward and the reasoning behind those decisions. It will help clients to take better decisions.
Give enough time for migration
Effort required to migrate from an old API to a new one could be small or big depending on the functionality (please make no assumptions here). Every team works based on their priorities and hence it is important to give enough time for clients to migrate. Old API has to be supported with bug fixes till the agreed upon deadline.
Following are few things that can be done at the organization level.
Centralized API review team
Typically, every API will be designed, reviewed and approved by domain architects. This is absolutely fine since they have better knowledge about the goals of a service and its future direction. Once it is approved by domain architects, it should be presented to a centralized team to get the final approval. Centralized team should be independent of the domain and they should validate and approve APIs from the client’s perspective.
Centralized API explorer
A centralized repository of all APIs exposed to internal clients within an organization. It should be well categorized and searchable with keywords. It should have up-to-date documentation, versioning, playground and owner information. Clients should be able to rate APIs and share feedback to service owners. Clients should also be able to subscribe to an API so that they will get notified whenever the API is modified.
In summary, exposing APIs to an internal client should be treated in the same way as for external consumers. It has to go through the same design reviews, processes and quality checks to make sure the APIs are well-designed, documented, easy to use and maintain. It will be very easy to expose some of those APIs to partners or external consumers in case your organization decides to do so.
Please share your opinion or comments below.