As the number of devices, applications, tech advancements — and user expectations — continue to grow, finding effective ways to manage APIs is a more pressing need. Here are the answers to some pervasive questions about API management.
Are microservices applications making API management more complicated?
Certainly. There are fundamental aspects of API management for microservices that simply aren’t well-served by existing standards and tooling in the space. Take authorization. If you have a monolithic API gateway fronting a handful of services, it’s relatively easy to reason about things like access by issuing scopes to callers and using the identity of the caller to decide what the caller is allowed to access. You have one entry point into your ecosystem and one point to decide whether the caller is allowed access.
But if you really want to embrace microservices, if you really want services to be called in near infinite patterns, there is no gateway. Your callers are addressing services directly, and it’s thus impossible for any service to make assumptions that all callers have been vetted by a gateway. Your services need to take an adversarial stance with each caller, doing their own validation that the caller is who they say there are and, just as critically, that the caller is allowed to perform the actions requested.
This alone adds a fair amount of ceremony to each service. It’s not uncommon for a service with 1,000 lines of business logic to spend at least half that much on validation/authorization logic, so the overhead of request handling becomes a meaningful tax on each incremental service you roll out. At the point where you spend as much time validating callers as you do servicing their requests, you may rightly wonder whether microservices are worth the fuss.
Are other trends also creating a bigger API management workload?
I think the real tug is between developers creating more and more fine-grained services (where the temptation to do things differently enough from API to API, thus annoying callers, is hard to avoid) and offering these services to more and more callers, particularly callers of varying degrees of sophistication.
There aren’t obvious ways to address this. If you try to stand up a monolithic façade in front of your APIs that hides the gory details of your microservices from your customers, you’ve taken away a lot of the benefit of having services that can be developed autonomously, as stand-alone products (the service developers need to wait for the façade developers to link up any new changes). But if every microservice developer spends the majority of their coding time complying with standards and validating requests, you’re creating tons of duplicative work that eats into the value of giving each microservice developer autonomy to solve business problems.
What elements should an ISV or software developer have in their API management strategy?
Treating APIs as products consumable by someone other than the developer sitting next to you requires a lot of care and coordination that isn’t often appreciated:
- You need to know how you are going to authenticate your callers and validate their access.
- You need to know how you’re going to manage the lifecycle of your API: once it’s out there and you have a single customer calling it, you’ve established an implicit or explicit contract with that customer. If you make a change that breaks their software, you’ve broken your API and that contract.
- You need to know all the little fiddly details on how you are going to name/case/capitalize every aspect of your API.
- Every developer in your ecosystem needs to agree to do all these things the same way, or you really don’t have an API ecosystem.
Are there tools that can help with API management?
As always, have someone else solve as much of the problem as possible. If it’s not core to your business, find a vendor that does it (though you do want to weigh the extent to which you could get locked into the quirks and design of a specific vendor).
We also use New Relic pervasively for monitoring our ecosystem. Each service might be built on a completely different tech stack, but with New Relic we have shared visibility of who is calling whom, where errors might be creeping into the system, etc. Of course, it’s critical for each team to monitor their own set of products, but it’s even more useful for the holistic visibility it gives us into dependencies. It’s how we maintain and validate our SLAs with each other.
We use a vendor (Auth0) for identity management, and for an organization of our size, with over 10,000 employees and contractors across over a dozen different organizations, each with their own identity infrastructure, it’s been a huge help to have a vendor smooth over all those differences. Every Cimpress employee can easily log in to our internal tooling and get a token to call any of our APIs, and this is all facilitated by the vendor. Every Cimpress employee can also log in to our dozens of external SaaS partners, again with their identity secured by Auth0 and open standards (SAML) back to those vendors. It’s a huge amount of tedious work we don’t need to do.
What are the best ways to make APIs accessible?
I think the answer here is probably the same as the above: pick a vendor you prefer to host your APIs while relying on the most broadly-adopted open standards (OpenAPI) to document your interfaces. I’m leery of proprietary API declaration languages because so much tooling already exists for OpenAPI, so even though the alternative spec Blueprint (Apigee) is open source, it’s still more tied to a vendor’s ecosystem than I would prefer.
Beyond making your APIs accessible as in “findable,” we’ve put a lot of standardization effort into making our APIs accessible as in “consumable.” One risk with microservices is that you’re empowering each team to choose their own tools and build their own APIs, and through preference, personality, or lack of attention to tiny details, you wind up with hundreds of services that look different enough to annoy a consumer. Even simple things like casing and capitalization in your responses can add up in the mind of consuming developers, making your microservices feel like a collection of miscellaneous parts from different organizations than components of a coherent ecosystem.
To avoid this, we’ve embraced public standards where available (for pagination, for example) and created our own standards through an internal RFC process elsewhere. Some examples of things we standardize to avoid fragmenting the caller experience include:
- All APIs are RESTful and documented with OpenAPI.
- All APIs that return more than N results support pagination that looks like Y.
- All APIs use the same capitalization and casing in routes, requests, and responses.
- All APIs accept OAuth2 Bearer tokens signed by the same vendor.
- All APIs are responsible for validating the access requested by the caller, and (this is a crucial plank of our security approach, see below) all APIs pass the identity of the caller to any other APIs they are calling.
What’s the best way to address API security?
This is a deeply complex topic, and the truth is, there aren’t existing standards that make this easy to handle, particularly if you need to consider access at the level of resources.
As I mentioned in another example above, we’ve taken microservices to their logical extreme: every service is accessible on the public internet and callers can hit those services without any sort of gateway making authentication or authorization decisions. It’s entirely the responsibility of the service to handle authentication then, since every service needs to be its own self-contained entity.
One of the standards we’ve embraced to support this is that services never identify themselves to each other as service accounts or any other elevated authentication. A service always passes on the identity of the caller when it needs to call another service in our ecosystem. This is to avoid a common attack vector/source of developer errors where the called service needs to trust that the caller will do something responsible with the returned data because you don’t have any clear mechanism of communicating the responsibility to them as your service mesh gets broader and deeper.
Again, these aren’t problems you have if you have one big API gateway and a relatively small number of publicly addressable services, and most authentication and authorization schemes haven’t caught up to the reality of microservices.