REST, or in the full form, Representational State Transfer has become the standard design architecture for developing web APIs. At its heart REST is a stateless client-server relationship; this means that unlike many other approaches there is no client context being stored server side (no Sessions). To counteract that, each request contains all the information necessary for the server to authenticate the user, and any session state data that must be sent as well.
REST takes advantage of the HTTP request methods to layer itself into the existing HTTP architecture. These operations consist of the following:
- GET - Used for basic read requests to the server
- PUT - Used to modify an existing object on the server
- POST - Used to create a new object on the server
- DELETE - Used to remove an object on the server
By creating URI endpoints that utilize these operations, a RESTful API is quickly assembled.
In this sense an API - which stands for Application Programming Interface - allows for publicly exposed methods of an application to be accessed and manipulated outside of the program itself. A common usage of an API is when you wish to obtain data from a application (such as a cake recipe) without having to actually visit the application itself (checking GreatRecipies.com). To allow this action to take place, the application has published an API that specifically allows for foreign applications to make calls to its data and return said data to the user from inside of the external application. On the web, this is often done through the use of RESTful URIs. In our cake example the API could contain the URI of
The above is a RESTful endpoint. If you were to send a
GET request to that URI the response might be a listing of the most recent cake recipes that the application has, a PUT request could add a new recipe to the database. If instead you were to request
/cake/141 you would probably receive a detailed recipe for a unique cake. These are both examples of sensible endpoints that create a predictable way of interacting with the application.
The API that we’re going to construct here will consist of two classes. One Abstract class that will handle the parsing of the URI and returning the response, and one concrete class that will consist of just the endpoints for our API. By separating things like this, we get a reusable Abstract class that can become the basis of any other RESTful API and have isolated all the unique code for the application itself into a single location.
However, before we can write either of those classes there’s a third part of this that must be taken care of.
.htaccess file provides directory level configuration on how a web server will handle requests to resources in the directory the
.htaccess file itself lives in. Since we do not wish to have to create new PHP files for every endpoint that our API will contain (for several reasons one of which being that it creates issues with maintainability); instead we wish to have all requests that come to our API be routed to the controller which will then determine where the request intended to go, and forward it on to the code to handle that specific endpoint. With that in mind, let’s create a
Let’s walk through this file. The first thing that we do here is wrap everything in a check for the existence of
mod_rewrite.c; if that Apache module is present, we can continue. We then turn the
RewriteEngine On and prepare it to work by giving it two rules. These rules say to perform a Rewrite if the requested URI does not match an existing file or directory name.
In the next line declares the actual RewriteRule. This says that any requests to
api/v1/ that is not an existing file or directory should instead be sent to
(.*) marks a named capture, which is sent along to the
MyAPI.php script as well in the request variable through the use of the $1 delimiter. At the end of that line are some flags that configure how the rewrite is performed. Firstly,
[QSA] means that the named capture will be appended to the newly created URI. Second
[NC] means that our URIs are not case sensitive. Finally, the
[L] flag indicates that mod_rewrite should not process any additional rules if this rule matches.
.htaccess file in place, it is now time to create our Abstract Class. As mentioned earlier, this class will act as a wrapper for all of the custom endpoints that our API will be using. To that extent, it must be able to take in our request, grab the endpoint from the URI string, detect the HTTP method (GET, POST, PUT, DELETE) and assemble any additional data provided in the header or in the URI. Once that’s done, the abstract class will pass the request information on to a method in the concrete class to actually perform the work. We then return to the abstract class which will handle forming a HTTP response back to the client.
Firstly we’re going to declare our class, its properties, and constructor:
abstract class API
By declaring this an abstract class we’re prohibited by PHP from creating a concrete instance of this class. From there we can create some protected class members. A protected member can only be accessed in the class itself and children thereof, unlike a private variable which can only be accessed in the class that defined the member.
One of the core premises of an API is that clients on different domains than the one the API is hosted on will be connecting to the API to send and receive data. There is an inherit security risk here, as this can allow an attacker to create an imitation page and steal data sent back and forth. Therefore this ability must be explicitly enabled on pages that wish to allow what is called Cross-Origin Resource Sharing, aka CORS. One excellent resource to learn more about CORS is the website Enable CORS - it was quite helpful to me as I was trying to understand things.
For our API we need to make sure that this is enabled, so the very first thing that is done in the
__construct method is to set some custom headers. The first two are the magic; firstly we allow requests from any origin to be processed by this page, next we allow for any HTTP method to be accepted.
Once the surprisingly simple yet completely crucial step of allowing CORS requests has been completed, it becomes time for our script to understand what the client has asked of it. To do that we’re going to take the $request variable which will be sent to our script from the .htaccess file (remember? it contains the original URI that the client requested), and tear it apart into the components we need. Once it’s been exploded around the slash by pulling off the very first element we can grab the endpoint, if applicable the next slot in the array is the verb, and any remaining items are used as $args.
The HTTP method will describe the purpose of this request. GET requests are easy to detect, but DELETE and PUT requests are hidden inside a POST request through the use of the
HTTP_X_HTTP_METHOD header. Once a method has been picked, the appropriate data source is parsed and cleaned for safety before being executed.
The rest of the Abstract class comes next. Right now we’re missing a function that will call the methods in the concrete class, and then one that will handle returning the response. Here’s the rest of the abstract class:
abstract class API
The one function worth mentioning here is the
processAPI() method. This is the one publicly exposed method in the API, and its job is to determine if the concrete class implements a method for the endpoint that the client requested. If it does, then it calls that method, otherwise a
404 response is returned. The rest of the new code is simply an array map of all the possible HTTP codes and an input sanitizer.
That’s all there is for the Abstract class. Now, finally time to implement a Concrete example.
Think back to our talk earlier about Cross-Origin Resource Sharing (CORS). Remember how it introduces a security vulnerability? We’re going to work to close that as tightly as possible here by tying an Origin to a unique API Key. This means that only known and allowed external hosts will be able to connect to our API service through a pairing of their domain name and a uniquely generated API Key. For the purposes of this example I’m going to leave some of the code to verify the API Key abstracted out. Additionally our API will require a unique token in every request to verify the User.
Creating the concrete class is as simple as that. For each additional endpoint you wish to have in your API, simply add new functions into the MyAPI class whose name match the endpoint. You can then use the $method and $verb and $args to create flow paths within those endpoints.
To actually implement the API we need to create the PHP file that the .htaccess file is forwarding all of the requests to. In this example I named it
// Requests from the same server don't have a HTTP_ORIGIN header
If you visit
/api/v1/example (and have the User and Token system setup) you should see the output from that endpoint there.
That’s all there is to it…which is, well, really quite a lot actually.