So there you are. Your team has a set of API endpoints to expose to their users. This API will change how your users interact with your services or services with other services. But how do you build metrics gathering, rate limiting, and quota policies into those endpoints to protect all of your users? And what about that legacy application that also needs to access these APIs, but doesn’t speak REST? Sure, you could build all of this in yourself, but with the availability of multiple API gateway products, it’s worth considering these low-code options.
When evaluating an API Gateway, as with anything, it is important to first understand the desired outcome. Perhaps you need to safely package your APIs for use by a third party, outside your organization. Or maybe you are planning to decompose your monolithic backend system into microservices, and you need an API middle tier to limit the disruption to your users. Or maybe you just need to secure your APIs against DDOS attacks, or spikes that could take your service offline. In this post, we will examine these use cases specifically, and how they can be implemented in Apigee Edge, as well as other alternatives such as Spring Cloud Gateway, and Ocelot.
The Tools
Apigee Edge
While many API gateways do solve similar problems, each have their own differentiations in the market. Some, like Apigee Edge, are market leaders in their category. Not only does Apigee function as a gateway, but also has deeper management functionality like metrics gathering, route tracing, and authentication frontends. It even has features that allow you to package and deliver your API product to developers. Apigee is a big platform with a ton of features, and having been recently purchased by Google it is worth adding into and API evaluation. But sometimes, if your organization does not need the power of such a large platform, these features can get in the way. A leaner, more focused gateway product may be what you need.
Spring Cloud Gateway
At the other end of the spectrum there’s Spring Cloud Gateway (SCG). SCG is a lightweight Spring component for developing your own API gateway. It is a powerful tool for performing the primary tasks of a gateway, while getting out of your way to allow your team to develop APIs faster. SCG is completely open-source and sponsored by Pivotal. And while Spring is most commonly associated with Java applications, there is no such limitation in the APIs which SCG can administer so you can use it in a polyglot environment just fine.
Ocelot
Right in between Apigee and SCF is Ocelot. With so many API gateways to choose from how did Ocelot make the list? Simple, .NET developers are being directed by Microsoft. It’s written in .NET standard, so for .NET teams managing it, it’s a breeze. It runs on both Linux and Windows, so it could be added in to legacy code that is looking to be containerized as well as modern cloud-native .NET.
The Evaluation
When evaluating platforms, it's easy to get wide-eyed thinking about the ‘art of the possible’ and lose sight of the development priorities that spurred you to look in the first place. With this in mind, we are going to consider Apigee Edge, SCG, and Ocelot through the lens of three fundamental use cases.
Rate Limiting: API rate limiting can come in the form of quota policies or spike arrests. Quotas are definitions of business logic and rules (i.e. this group of users can only access these APIs, at some rate, during some time). Spike arrests are more closely related to security policies and keeping the backend systems from crashing due to traffic spikes (user spikes, amplification attacks, and the like).
Service Hiding: Often with REST APIs, we only want to make a subset of endpoints available to outside teams. Certain endpoints may simply be for service-to-service communications, while others may be for the development team to manage those services. For some gateways this is about limiting through access controls. For others it’s about which endpoints are made available in the service registry. In any case, service hiding is a must for any API gateway. This allows API developers to only surface certain endpoints to users, while keeping others invisible.
Application Modernization: Maybe you have a monolithic backend application that is currently running your business. You want to start refactoring it into microservices by segmenting pieces of functionality and refactoring them to run as independent units, but you can’t afford to take downtime or to continually update the front end applications to point to the new microservices as they come online. And an API gateway can help here by providing a consistent API experience to users, while giving the modernization teams a chance to build the new services, test them alongside the existing app, and then cut over without disruption to existing users.
Apigee Edge
Rate Limiting
Spike Arrests: Spike arrests are implementations of a security policy. Primarily they are used to limit calls to an API in order to protect backend infrastructure from being swamped and going down altogether. It’s better to limit serving to some users than to have the system go down for everyone. Spike arrest policies are typically based on time (no more than N calls in T time) and unlike quota policies, are usually blanket policies aggregated across all users.
To create the spike arrest policy, first go to API Proxies in the left-hand navigation bar, then click + Proxy. Select Reverse Proxy, and fill in the fields as you need. For our example, we are just using httpbin.com/get for our endpoint. Then select Pass Through for authentication, and accept the defaults for the rest.
Next in the Preflow section, we are going to add a step, and insert the spike arrest policy. We then modify the default XML for our purposes (all gateway code used for this demo is available on GitHub). Here we are just going to limit requests to and save the revision. That’s it!
In the following GIF, we show these steps along with using the embedded trace tool to show gateway functionality before and after the spike arrest policy is implemented.
Quota Policies: As discussed above, rate limiting can come in a couple of different flavors: quota policies, and spike arrests. Here we will look at quota policies in Apigee Edge. These policies can be configured with very granular controls. Users can limit a group of users with a time-based policy (no more than N calls in T time), or by assigning arbitrary “weights” to certain attributes of the call (like the HTTP verb). This list of configuration options is by no means exhaustive but should give you some idea of the types of controls available.
Here we are just going to create a simple time-based quota policy for an endpoint. To create this, we are going to continue where we left off with the Spike Arrest policy from above. First we need to modify the spike arrest policy so the two policies do not conflict. 3,000 requests per minute ought to be enough to make sure we hit the Quota policy, and not the Spike Arrest policy in our trace tests.
Next, again in the Preflow section, we are going to add another step and insert the Quota Policy. Then we’ll modify the default XML to suit our needs (again, all code is available on GitHub). Here we will set the quota limit to 2 per minute, again for demo purposes.
In this GIF, we will show the modification of the Spike Arrest policy and subsequent trace test to show that the endpoint is working as expected. Then we will add the Quota Policy and modify the XML, finally performing another trace test to show the Quota Policy kicking in.
Service Hiding
While typically hiding an API endpoint should come down to good API hygiene (if you don’t want it exposed, don’t expose it), there are some instances where you do need to expose an endpoint, but tightly restrict access to it, such as limiting source IP addresses. This is what we are going to do in Apigee Edge.
To show this, we are going to create a new interface. And in these steps we are going to show off another feature of Apigee Edge, importing OpenAPI specifications. Like before, we are going to the API Proxies section and clicking “+ Proxy”. But this time, instead of clicking on Reverse Proxy, we are going to select the Use OpenAPI option. Under the Import From URL tab, we will add a descriptive name, and a URL. For this demo we are going to use a set of demo endpoints Apige makes available for testing, here. With this, click next. Set auth to Passthrough, and accept the defaults for the rest.
To set the policy, we are going to add a step and select the Access Control Policy. Select one of the endpoints in the Develop tab, click + Step, and select Access Control. Here we are going to modify the XML to accept only my IP address, and reject all others.
One caveat: I am on a consumer-level internet connection so my IP address is not static. There are some hiccups in the following video where connections get rejected, but this also allows a view into how to troubleshoot problems in Apigee.
Application Modernization
Here we are going to show how to use Apigee Edge to provide your developers with a REST interface, while translating those requests to SOAP calls. In this way, a consistent and modern developer experience based on a REST API can be provided to your users, while parts of your traditional backend SOAP system are refactored to take advantage of cloud native design paradigms.
Again we are going to create a new endpoint, this time selecting the SOAP Service option. We are then going to choose one of the prepackaged Example URLs. For this demo I chose the Delayed Stock Quote option. Validate the URL. As always for these demos, select Passthrough authentication, and keep default options until the endpoint is created.
That’s it! Go start a trace session and from the base URL and add the /quote endpoint with the query params ?StockSymbol=PVTL&LicenseKey=0 – or whatever other ticker symbol you want to look up. In this case the LicenseKey is just a dummy value necessary for testing. Apigee will take that REST call and transform it for the SOAP service. Then in turn, Apigee will take the XML response and form it into JSON automatically. Pretty great!
Here we will show these steps. First creating the Proxy, then testing it with the trace calls to the endpoint we defined. At the time of creating this, the /quotes service wasn’t actually returning any useful data even when accessed directly, but you get the idea.
For more information on these Apigee Edge examples, the “Four Minute Videos for Developers” (4MV4D) YouTube series is a great place to start and informed the demos seen here. Secondarily, the Apigee Docs are also a good place to get started, and are also full of examples. And again, all endpoints we have discussed here have been exported and are available on my GitHub repo.
Spring Cloud Gateway
Rate Limiting
The paradigm which Spring Cloud Gateway (SCG) uses to implement rate limiting is that of a filter. In this way, every request to the API is passed through a filter which uses a RateLimiter implementation and an optional keyResolver interface to ensure that the limit which was implemented has not yet been reached.
Here is an example keyResolver interface:
public interface KeyResolver { Mono<String> resolve(ServerWebExchange exchange); }
Additionally, if you are already using Redis, there is an implementation of a rate limiting quota using the keyResolver interface from the previous example along with a YAML definition to implement replenishRate (how many requests per second you want to allow through the API) and burstCapacity (an optional additional capacity for bursts of requests).
Example YAML definition:
spring: cloud: gateway: routes: - id: requestratelimiter_route uri: http://example.org filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20
Example Config.java:
@Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); }
These examples, as well as additional information on configuring quotas in SCG can be found here.
Service Hiding
In SCG, service hiding is more about giving the user control over what is exposed, as opposed to controlling views into exposed endpoints. Spring Cloud Gateway allows you to route traffic to your APIs using simple Java™ instructions (which we saw in the last article) or with YAML configuration files (which we’ll demonstrate in this one). To hide your services, you set up your network so that the only server accessible from the outside is the gateway. The gateway then becomes a gate-keeper, controlling ingress and egress from outside.
Spring Cloud Gateway also uses the Spring Cloud Netflix Eureka Server as a service registry. Cloud-based services have a habit of changing location and granularity without much warning. To cope better with this, a combination of a gateway with a service registry will allow the applications on your network to find each other dynamically at runtime. If you do this, your applications will be much more resilient to changes. Spring Cloud Netflix Eureka Server is one such service registry.
A recent blog post on spring.io/blog shows how to get a demo environment up and running so you can get both SCG and Eureka up and running, and serving API traffic
Application Modernization
In this case, using SCG is more about API redirection. In this case you may have a monolithic backend system which you do not want to expose to your developers directly, so you route them through SCG, which presents a consistent and modern set of APIs.
Adding this functionality is straightforward in SCG. Once you have a project created simply add a Bean to the application. For example:
@Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { return builder.routes() // Add a simple re-route from: /get to: http://httpbin.org:80 // Add a simple "Hello:World" HTTP Header .route(p -> p .path("/get") // intercept calls to the /get path .filters(f -> f.addRequestHeader("Hello", "World")) // add header .uri("http://httpbin.org:80")) // forward to httpbin .build(); }
Here we are adding a simple reroute from our API to httpbin.org. Rather than exposing the API directly, we can now use the gateway to present a new API design, secure access, or a number of other functions available in Spring Cloud Gateway.
Ocelot
Rate Limiting
Similar to Apigee Edge’s quota policies, limiting the traffic to an Ocelot managed API is simplistic in its approach. You define the rules for each endpoint, as opposed to rules globally for the app. This may seem like too much overhead as endpoints add up, but remember Ocelot is JSON based. Which means you can easily create scripts to do all the hard work.
The options for creating a rule are:
-
ClientWhitelist: this is a list of clients that won’t be affected by the rule. Client in this context refers to the value of a header labeled ClientId.
-
EnableRateLimiting: yes/no if the rule is enabled.
-
Period: the window of time to allow N requests through. Think in terms of seconds, minutes, days, etc.
-
Limit: the number of requests to allow through during the defined period.
-
PeriodTimespan: when the rate has been exceeded and the request is denied, the number of seconds they have to wait before requesting again.
Now with our rule(s) defined for each endpoint, we can customize a user’s experience when their request is denied. This applies to all apps the given Ocelot instance is managing.
The options for customization are:
-
DisableRateLimitHeaders: there are headers included by default in a response to a denied request, X-Rate-Limit and Retry-After. If you didn’t want to be that descriptive about things, they can be excluded from the response.
-
QuotaExceededMessage: is a simple string explaining to the user why their request was denied. The default is to include a quick description about the rule that limited requests (ie: 1 request per 1 second). You can choose to replace this.
-
HttpStatusCode: the default is to respond with a status code of 429. You can choose to provide a different code.
-
ClientIdHeader: tying back to the client white list defined above, the default is to use the “ClientId” header for identification. This can be changed.
Service Hiding
In Ocelot the goal of “service hiding” takes on a different definition. For a given endpoint, you can specify what “UpstreamHosts” are allowed to use it. This is tied back to the host header value of the request, and is specified as a collection of values.
If we wanted to only allow request routing from “somewhere.com”, the endpoint ReRoute config would be:
"UpstreamHost": "somewhere.com"
Then only requests with that host header value will be allowed through.
Application Modernization
Ocelot is a modern API gateway and in that vein, it assumes a code first approach to managing/configuring it. When you get in to edge case where there are no obvious built in features (which is commonly the case during app modernization), Ocelot gives you the chance to inject custom middleware. You can choose to hook the middleware to certain events that happen during the request/response life cycle. Read more here.
Thinking about converting an HTTP request to SOAP, you can use Ocelot’s ability to transform headers from a SOAP request to pass along quite easily.
Conclusion
In this article we looked at three similar use cases for three different API gateway platforms. In the end, whichever you pick is going to be up to your project, and how the tool fits into your workflow. For example, if your team is primarily focused around Java development, and particularly if you are already invested in the Spring ecosystem, Spring Cloud Gateway might be the most obvious choice. Likewise if you are a .NET team, or have a large Windows infrastructure platform already, then you might consider Ocelot. And if you prefer GUI applications, and a very full featured API Gateway + Management platform, then Apigee Edge on Pivotal Cloud Foundry might be the best choice.
For more information on modernizing applications, API platforms, and gateways, join us at the Spring One Platform 2019 conference this October.