Thick API Gateways

I came across the term ‘Overambitious API Gateways’ from Thought Works tech radar. The point is, whether is it good or bad to have business logic in the API Gateways? Since the term Gateway is not a functional requirement and serves the purpose of a reverse proxy; it is quite obvious that including business logic in an API gateway is NOT a good design. But the idea behind the overambitious API gateways, seems to be a finger pointing at the API Gateway vendors, rather than considering the solution design and development and how the API Gateways should be used.

I prefer the term ‘Thick API Gateways‘ over overambitious API Gateways because the implementation is up to the developer regardless of what the tool can offer. This ensures an anti-pattern.

With the advent of microservices architecture, API Gateways gained another additional boost in the developer tool box, compared to other traditional integration technologies.

giphy

Microservices favor the patterns like API composer (aggregation of results from multiple services) Saga (orchestration of services with compensation) at the API Gateway. API Gateways also host other business logic like authorization, model transformation and etc. resulting a Thick API Gateway implementations.

Having said, though thick API gateway is a bad design and brings some awkward feeling at night when you sleep, in few cases it is quite inevitable. If you’re building a solution with different systems and orchestration of the business flows is easy and fast at the API gateway. In some cases it is impossible to change all the back-end services, so we should inject custom code between the services and API gateways to achieve this, which would result other challenges.

At the same time, as developers when we get a new tool we’re excited about it, and we often fall into the ‘if all you have is a hammer, everything looks like a nail‘ paradigm. It’s better to avoid this.

giphy1

Let’s see some practical stuff; in fact, what kind of business logic the modern API gateways can include? For example, if we take the gateway service offered in Azure API Management (APIM), it is enriched with high degree of programmable request/response pipeline.

Below APIM policy, I have provided an authorization template based on the role based claims.

The API gateway decides the authorization to the endpoints based on the role based claims. The sections are commented, first it validates the incoming JWT token, then sets the role claim in the context variable and finally handle authorization to the endpoints based on the role claim.


<policies>
<inbound>
<!– validates RS256 JWT token –>
<validate-jwt header-name="massrover_token" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized"
require-expiration-time="true" require-signed-tokens="true">
<audiences>
<audience>audience id</audience>
</audiences>
<issuers>
<issuer>issuer id</issuer>
</issuers>
<required-claims>
<claim name="role" match="any">
<value>admin</value>
<value>moderator</value>
<value>reader</value>
</claim>
</required-claims>
<openid-config url="https://massrover.idenityserver/.well-known/openid-configuration" />
</validate-jwt>
<!– sets the role claim to the context variable –>
<set-variable name="massrover_role"
value="@(context.Request.Headers["massrover_token"].First().Split(' ')[1].AsJwt()?.Claims["role"].FirstOrDefault())" />
<!– performs authorization based on role claim and allowed http method –>
<choose>
<when condition="@(context.Variables.GetValue("massrover_role").Equals("admin"))">
<forward-request/>
</when>
<when condition="@(context.Variables.GetValue("massrover_role").Equals("moderator")">
<when condition="@(context.Request.Method.Equals("delete", StringComparison.OrdinalIgnoreCase))">
<return-response>
<set-status code="403" reason="Forbidden" />
<set-body>Moderators cannot perform delete action</set-body>
</return-response>
</when>
<otherwise>
<forward-request/>
</otherwise>
</when>
<when condition="@(context.Variables.GetValue("massrover_role").Equals("reader")">
<when condition="@(context.Request.Method.Equals("get", StringComparison.OrdinalIgnoreCase))">
<forward-request/>
</when>
<otherwise>
<return-response>
<set-status code="403" reason="Forbidden" />
<set-body>Readers have only read access</set-body>
</return-response>
</otherwise>
</when>
<otherwise>
<return-response">
<set-status code="405" reason="Not Allowed" />
<set-body>Invalid role claim</set-body>
</return-response>
</otherwise>
</choose>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>

Note: This is a thick API gateway implementation and the pros and cons of this is subject to the problem in hand. This above is a practical elaboration of one thick API implementation.

Advertisement

API Architecture – Distinguish between Web Application and API

A RESTful service is a common element in any modern system. But not all the RESTful service implementations are valid Web APIs. This first post of the API architecture series, covers the idea of separation of an API from the web application based RESTful implementations.

Often we see a figure analogous to the one below in many diagrams. Regardless of what the diagram is called, if we look at this figure the direct meaning it gives, is the separation of the API and the clients.

client and api

In web development, a Javascript client talks to the RESTful endpoints designed specifically for it. There’s nothing wrong in this implementation, it is perfectly fine, but the concern is – the system does not have an API. Having mere technical implementation of a RESTful service does not create an API.

In order claim an API based architecture, the RESTful service implementation should have the following characteristics.

 

#1 Individually deployable

API assemblies should be deployable in a separate instance without the consuming client. Often Javascript clients are deployed together with the RESTful service, because these clients are often developed along with the API. Separate deployment model gives the benefit of scaling the API when required.

#2 Stateless or centralized state management

APIs should be either stateless and get the state information from the client request or should contain a centralized state persistence. Centralized state cache is often an in-memory caching implementation like Redi.

#3 Avoid Client Commanded Implementations

I strongly advocate this point, developers sometimes tend to do this if they find performing the required view model construction in the client is not preferable. It is hard to draw the boundary, because some aggregate operations are better be performed in the server but some cases are pure violations, Example – assume an endpoint has response body like the below JSON payload.


{

id : 1,

firstName : "Thurupathan",

lastName : "Vijayakumar"

}

And having another endpoint just for the purpose of another view which has a response output like the following JSON payload is a violation.


{

id : 1,

fullName : "Thurupathan Vijayakumar"

}

The above example is a very simple one, but I have seen worst implementations that API has responses of color codes and CSS classes, where the reason was purely that developers did not want to write code in Javascript. I would call such cases as client commanded implementations.

(Back end for front end) BFF model implementations have different response messages based on the client, but that is different from view model construction. Also the features like sorting and pagination are not part of the view model construction.

#4 No cookies

A RESTful service which is exposed as an API should NOT accept any information in the cookies. This again happens with the tight coupling of web application with the RESTful service. Developers create a cookie and the consequent request from the Javascript clients to the RESTful service sends the information from the cookies. All data from client to the API should be in query string, request body or in HTTP headers.

#5 Documentation

This is not a must, but a near must for any API implementation. There are many documentation libraries available like Swagger, TRex and other API Management Gateways also provide good API documentation services.

#6 Authentication

Most public developer APIs are secured by the API keys. Ex – Google Maps. The key is often used not only in authentication but also in monitoring the request rates and etc. If the API is private (either to a single organization or few accepted parties) the recommended practice is to have an authentication. Mostly this is an OAuth 2 based authentication and there are several token formats whilst JWT being the well-known one.

With those concerns we can have a API implemented for the systems. There are many readings in based on the different aspects of the API, like documentation, hyper media, versioning, authentication, caching, scopes and etc. You can find ample amount of resources in the web sphere. This post gives the fundamental idea – separation of API and web application implementation. In the next post we will discuss more about implementing an API using the ASP.NET Core and EF Core stack.