Analytics and monitoring are excellent for business reasons, but the real solution to API abuse is to place controls around the execution of computationally expensive code. The threat of excessive hits can actually be completely avoided by setting access controls that throttle the number of requests a customer can make to the API in a given period of time. This practice is commonly referred to as rate limiting. Since web-based RESTful APIs usually imply an HTTP interface, this could be more accurately described as HTTP rate limiting, which is what most people think of when they think of throttling.
Advanced MVC Architecture
Laravel is a popular PHP framework because it brings an elegant and expressive code base to an otherwise ugly language. Beginners especially love Laravel since it allows even the most rudimentary applications to be built on the shoulders of an easy-to-assemble Model-View-Controller (MVC) architecture. Nearly every tutorial written on Laravel directs the novice engineer into this traditional software pattern and allows them to create a basic RESTful API with Laravel. This out-of-the-box functionality empowers developers and is testament to Laravel’s agility. That being said, Laravel is much more than just a MVC. Laravel is a framework of good code and in the hands of a capable programmer this framework can build complex yet maintainable applications.
When dealing with MVC architecture, complex applications will tend to introduce a natural hierarchy within the controller components. For instance, an engineer may have an API controller layer that strictly handles inputs and serves up JSON as the response format. The customer application might require another controller in front of this API controller. This front-end controller, often called a UI controller, takes the simple primitive (or perhaps another data-transfer object representation) from the API controller and passes it to the view composer. The view composer, in turn, creates HTML suitable for a front-end interface. Various patterns could be further introduced to make this hierarchy more composable and maintainable, but that is a subject for another article. What remains, however, is a more advanced yet organically derived MVC pattern that builds in natural hierarchy. Usually such architecture is called Hierarchical-MVC or HMVC for short.
Problems With the Scalability of Rate Limiting
Getting back to the rate limiting concept, the HMVC pattern presents a scalability problem. Now that there is hierarchy in the controller layer, two HTTP end points that now need rate limiting: one for the API controller and one for the UI controller. If there are more UI controllers or more hierarchy within the controller components, then this problem escalates. While many developers exploit this consequence of HMVC by providing different rates to the different HTTP end points (APIs have a significantly lower overhead than their UI controller counterparts), the duplicate rate limiting code problem remains. Sure Nginx or Apache will likely not mind this extra configuration and slapping more middleware onto Laravel's routes is not very costly. But the execution of the code will not scale as linearly when the rate limiting schemes get more and more complicated.
Imagine the executed code is a very expensive operation like crunching image data, or performing deep analytics map reduction, or some other taxing unit of work. The realm of HTTP rate limiting does not accurately represent the solution. Furthermore, as already stated, it leads to a duplication of efforts in handling the throttling of the same unit of work as initiated from different HTTP interfaces. Also, it is important to note that a console command is an entry point to your application, one that usually skips right past the HTTP layer and controllers entirely. The same could be said of anything like queue workers and other asynchronous processes that might also run the same unit of work but without an HTTP interface.
A resource throttling mechanism is needed that is decoupled from the HTTP layer of the application entirely. Using rate limiting on method calls with Laravel (or Lumen or any framework for that matter) takes some architecture planning. There are many rate schemes to choose from, including the simple hit counter shown in the following example. The scheme needs an implementation to control the rate of code execution. This implementation might rely on other framework-provided service classes such as Cache, DB, Auth, or others. Additionally, there is the need for a middleman or an agent service class that will forward method calls to the actual unit of work while at the same time delegating call throttling to the rate limiting code.
What Is A Proxy
Proxy is an agent or substitute authorized to act for another person. Wikipedia
The word proxy comes up naturally in the auction house where valuables are sold to the highest bidder. Often the buyer is not present or prefers to remain anonymous if their presence drives the price higher. In lieu of their presence, an agent is sent to bid on behalf of the real bidder. This agent is called a proxy and their bids are called proxy bids. They proxy bids for the bidder. A shareholder meeting is another place where proxies are often present when it is difficult or too expensive for a shareholder to attend. The proxy pattern works very much like these real world examples.
This article will demonstrate rate limiting by using the proxy pattern to intercept calls intended for the real unit of work. The calls are intercepted to add a new behavior that consists of checking the hit counter of the rate limiting service just before forwarding the call on to the original unit of work. The proxy pattern can be used for many more things than just rate limiting, but the pattern fits the needs of a throttling service nicely. In the example to follow, while the real class is present in the application, the proxy will do all the call handling.
Before getting to the implementation details, it is important to take a deeper look at the proxy pattern itself to understand its nuances, similarities, and differences to other common patterns. Learn it well and the proxy can be a tremendously handy pattern to solve otherwise complex problems. The proxy pattern consists of four unique components:
The customer is the class that needs the actual unit of work executed. It is the code that makes the call to the unit of work. Like a real customer or customer, it is requesting that a service be provided to it.
Based on the HMVC architecture described above, the customer class could be an API controller, a UI controller, or a console command. In technical terms, the customer is the class that depends on the real subject.
The subject is the real unit of work that is so expensive it needs to be proxied. It is the code that the proxy forwards calls to should the proxy decide it is necessary to execute.
Based on the HMVC architecture described above, the subject could be a class from the model layer (such as an Eloquent model), a repository, or another complex service. In technical terms, the real subject accomplishes the expensive work or contains a lot of data.
The wrapper is the interface that the proxy implements so that it can forward all of its calls to the real subject. The wrapper can be thought of as an abstraction of the subject's methods that need to be proxied. The proxy may not do everything the subject does, but it does everything the customer needs it to. The wrapper is the intersection of these two interfaces. The wrapper makes it possible to easily swap out the proxy for the subject.
Based on using a repository class as the subject in the HMVC architecture described above, the wrapper could be an interface for CRUD operations commonly needed by customer classes like controllers. In technical terms, the subject (wrapper) is an abstraction of the real subject.
The proxy is the class that conforms to the wrapper interface but intercepts all the calls to provide its own behavior. The purpose of the proxy is to provide the behavior that the customer is expecting as defined by the wrapper, but without making the customer any more aware that the real subject is not actually being called directly. This makes it possible for the proxy to provide behaviors before, during, and after the subject's method calls. The proxy does not even need to call the subject if the proxy has a local cache already, or if the proxy deems the execution too expensive. Instead, it could call the subject only when absolutely necessary or as part of a promise object (in an asynchronous operation).
Based on the HMVC architecture described above the proxy class would delegate to a rate limiting service the needed throttling behavior just prior to forwarding calls to the subject. In technical terms, the proxy provides the customer a reference that conforms to the subject (wrapper) while communicating with the real subject instance only when needed or allowed.
There are quite a few similar patterns to the proxy pattern and while many could be argued as more applicable to a rate limiting service, the point remains that a proxy often maps better to the real-world counterparts than the other patterns.
Proxy vs. Adapter
The adapter pattern is similar to the proxy pattern, but, strictly speaking, its intended use is more limited. Like the proxy, the adapter does forward all of its calls from the customer to the subject. Unlike the proxy, however, it does not add additional or alternate behavior. The adapter is more similar to the façade than it is to the proxy. The proxy changes the behavior of the subject, but preserves its interface, while the adapter changes the interface of the subject but preserves its behavior. A customer would use the proxy in the same way it would use the real subject and often does so with no knowledge that it is. A customer would not, however, be able to communicate with the subject the same way it would the adapter in an adapter pattern implementation.
Going back to the real-world example of an auction house, if the proxy pattern was the bidder's agent, the adapter pattern would be the bidder's language interpreter. The customer is intending to communicate directly with the subject but cannot without the adapter present. In the same way, an auctioneer cannot accept bids in a foreign language without an interpreter.
Proxy vs. Decorator
A pattern that is most often confused with the proxy is the decorator pattern. While the decorator pattern is very similar to the proxy pattern in its UML diagram, the intended use is slightly different. A decorator is intended to add behavior dynamically to subjects so that they can work like the customer expects, while a proxy is intended to add behavior to an otherwise perfectly usable subject for the purposes of controlling customer access. The decorator is the subject all fancied up while the proxy works on behalf of the subject. Both patterns add their behaviors to the subject in such a way that the customer is completely unaware that they are not communicating with the real subject and so to that point they both demonstrate decoupling well.
Decorators often receive their subjects as constructor parameters and thus enjoy the benefits of superclasses without the drawbacks of inheritance. That said, do not look for constructor injection as the distinction between the patterns. Instead, look for how the classes are used to determine which pattern is at play. Using Laravel's IoC container and dependency injection, it is quite possible that the proxy pattern is being used but looks an awful lot like a decorator based on its class construction.
Again referring back to the real-world example of an auction house, if the proxy pattern was the bidder's agent, the decorator pattern would be the bidder disguising their identity or embellishing their appearance to blend in. The customer is intending to communicate with known subjects, but the real subject is lacking the necessary functionality and so the decorator provides it. The decorator is like the uninvited bidder at a private auction who must look like they belong among the high-society crowd in order to bid.
Proxy vs. Façade
A pattern that is seldom confused with the proxy but often appears in the same system that involves a complex proxy is the façade. The utility of the façade is similar to that of the adapter but with the sole purpose of making the interface simpler. Like the proxy, the façade will forward the customer's calls to the subject but will do so with a more idealized wrapper interface. Like the adapter the façade is not supposed to introduce any new behavior, but rather abstract away the concerns of implementation from the customer by providing a simpler interface. This tends to make the façade a very large class compared to their adapter alternatives. While the proxy adds behavior, the façade simplifies it to the point of removing unnecessary behavior. If the customer code is coupled to the interface the façade provides, then usually this means that while the proxy is optional within the system, the façade is not.
Since this article is discussing proxies within the Laravel framework, it would be bad form if Laravel's facades were not mentioned. Laravel's service locator classes are often called facades and should not be confused with the façade pattern. While aptly named facades because of their ability to simplify service access, Laravel's facades are not technically an implementation of the façade pattern. They do provide a static call interface (which some consider a simplification), but under the hood these classes locate the intended service and then call that service's method instead.
Taking a real-world example from the auction house, there are a variety of ways to conduct an auction. The silent auction is where everyone writes their name down on a sheet with a high bid. This is not always efficient, though it does provide for multiple items to be auctioned off simultaneously. Bidders could just raise a hand as the auctioneer calls out bids, but this could lead to accidental bids and bidder confusion, as hands look alike. Bidders could call out their name instead, but in a crowd the chances that multiple people could have the same name might be problematic. Furthermore, their voice may not heard by the auctioneer and in the case of an anonymous auction, their voice could even reveal bidder identity. This is all simplified by using paddles, which cannot be confused with bidder hands. Instead of names, numbers are assigned to each paddle. If the proxy pattern is the bidder's agent, the façade would be the bidder's paddle number. The paddle number does not provide any new functionality, but rather lets the agent place bids in a way that is uniquely identifiable by the auctioneer, efficient for bidding, and yet still anonymous to the other bidders. It is the ideal way to bid.
It is now time to take the theory behind the proxy pattern to the practical level. In Part 2, this article will demonstrate one possible solution to the problem of rate limiting method calls within a Laravel application. There are many ways to implement the actual composition of a rate limiter. Remember that traits, abstract proxies, and even other PHP patterns might be better suited to a specific application needing a rate limiting scheme. The proxy pattern can even be implemented into a single class, using methods as forms of pattern encapsulation, instead of broken up into multiple classes as will be shown in Part 2.
Continue Reading: Learn more about the versatility of the proxy pattern by looking at a complete integration with Laravel and a rate limiting scheme. Continuing with Using Rate Limiting on Method Calls With Laravel Part 2.