An API Gateway acts as a coupling device between clients and backends. Its goal is to restrict knowledge the client needs to have of the backend. The client should be able to use the API gateway using very simple constructs. Whether authorizing requests or fetching a customer’s account information, the client should not have to know the details of the implementation - which service houses the logic, or where the data lives. Instead, the client knows about a single point of entry and is able to map user actions to the API gateway.

It is the job of the API gateway to map to implementation services. The API gateway should not maintain state. Instead it should convert a given client request into one or more requests to other services. Once an API gateway begins to maintain state, it is no longer an API gateway; it becomes a logic or data service. This is bad because it ends up muddying the waters between services which provide logic or data functionality, and the simple mapping of that functionality to the client. Effectively, an API gateway is a function composition service. Chris Richardson, founder of the original CloudFoundry and well known in the microservice community, discusses API gateways under this context in Building Microservices Using An API Gateway. I recommend reading his book, Microservice Patterns, partially available at Manning Publications.

Organizations attempting to place an API gateway in front of existing legacy systems should beware. It is easy to give in and incorporate business logic in the gateway layer. This can be particularly tempting if the legacy system is a poorly designed monolithic application with tons of spaghetti code. In keeping with the principal that no state should be stored in the API gateway, application logic and data should be housed external to the gateway. As long as this strict division of responsibilities is adhered to, improvement efforts on the part of the legacy application can involve modularizing and encapsulating functionality, which should then be moved into their own separate services. You might be wondering why it's so important to keep domain logic out of the gateway layer. Simply put, the moment domain logic gets added to the gateway layer, it is no longer a modular gateway; it becomes yet another monolithic application. In addition to the existing legacy system, you now have what will become two legacy systems. Remember the API gateway is a composition service component. Composition is, by definition, the mapping of smaller, bounded units that are mapped onto a larger domain.

I mentioned earlier that state should never be handled by the gateway. I partially lied. Caching can be done via the gateway and is often an included feature in commercial options. However, as an old adage states: the two hardest things in computer science are naming things and cache invalidation. It’s important to be sure that you have a good mechanism for maintaining and clearing cache. While caching is a useful tool for performance optimizations, failure to invalidate cached data can be fatal. It can be difficult to even determine if something is being improperly cached until it’s too late. Invalidation of cache requires that the cache control mechanism knows when staleness has occurred. This is non-trivial, an entire topic of its own and not in scope here. However, one consideration—depending on requirements—is to handle caching outside the API gateway. Rather than caching results at the API gateway, perhaps cache results in a given service. This allows for higher levels of customization per service as opposed to relying on a one-size-fits-all solution. The entire point of micro services is to have granular control of each logically bounded component of the system without negatively impacting the entire application.