Whether you’re building an add-on for a client project or plan to sell your add-on commercially, building an API so other code can access your add-on is a great idea.
There are several advantages to building an API for your product:
- It can increase adoption of your software, many companies have sped up their growth by offering an API.
- It allows other developers to provide future functionality and solve problems using your core product.
- It leads to better code; you are forced to think about the issues other developers will face in using your software. This can make you a stronger developer.
So how would we go about implementing an API in our add-on? First let’s talk about what makes a great API. Great APIs must be:
- Understandable, if it’s hard to use then no matter your features developers wont use it
- Secure, you want to make sure only valid allowed programs have access and user data is protected
- Versioned, you have to plan for new features without breaking apps using older code
- Graceful in handling errors and send back clear and understandable error codes to help the developer using your api diagnose problems
Now that let’s talk about actually building the API. For this article I created a sample add-on called the A-Team Mission Tracker to help my favorite soldiers of fortune track their missions.
So how are external apps going to communicate to our ExpressionEngine add-on? We’ll need to make sure we can expose API methods that respond correctly to GET and POST requests. Typically in CodeIgniter you would simple create a route to respond to API requests, however ExpressionEngine overrides CI’s routing to route requests to EE’s controllers. There’s no way to get around it without making modifications to EE’s core files.
Since modifying core EE files is out of the question for our add-on, we have to find other way. Actions are how EE runs code in core and third party add-ons, they support GET & POST requests and can render JSON & XML.
This sounds great, unfortunately there’s a major problem with EE Actions. Here’s what they look like:
Can you tell just from looking what API methods these URLs map to? Actions fail the “Understandable” criteria big time. Also, Action IDs vary from environment to environment and there’s no way to easily distribute it to other developers.
Fortunately there’s a way to call our API methods without having to use Actions or modify EE core. The key is to use EE’s “sessions_start” extension hook which fires every time a request is made.
Using this extension in the Mission Tracker add-on is as easy as creating an extension class, Mission_tracker_ext, and with a method that will respond to the session_start extension hook.
To explain this method, let’s assume the following GET request is sent to EE, “/api/mission/show_all”:
- Line 29: checks the first url segment against an API trigger word (“api”) if it doesn’t match we ignore the request, otherwise we move on to
- Line 34-35: we check the second url segment (“mission”) if there’s a match it calls CodeIgniter’s loader class (also available in EE). We use the actual segment for our class name. In this example we’re loading the “Mission_lib” API class.
- Line 38: finally we call the “call_method” method and pass it segment 3 (“show_all”), “call_method” will then go into the Mission_lib class and execute the “show_all” method returning a JSON formatted response of missions.
Let me explain the loader class in detail, you can see we passed in a third parameter to “load->library()” on line 35, this powerful parameter let’s us dynamically load any library we want and define a bookmark to it, for example “mission_api.”
Then in line 38, we just use “mission_api” to refer to our class, as long as the class has a “call_method” method, we’re able to use it.
Remember how we said call_method will actually run the API method in the loaded class? Line 21 is how it does it, PHP will execute the $method variable in the class.
By organizing the API around “trigger/resource/method” we can extend the API simply by adding more resource classes (ex. Equipment_lib, Vehicle_lib) and route_url doesn’t change. As long as the resource class implements the call_method method route_url can use it. In order to make it easy, I put the call_method function in a base class that the rest of my resource classes extend.
There’s a lot I didn’t cover in this article, some notes about security and other best practices:
- You can go deeper to secure your API, but at the very least create randomly generated API keys for registered apps. Force the apps to send the get in POST requests (you want to avoid using URLs as the key can be written to server logs). Reject requests that don’t have the proper key
- Use SSL, or HTTPS. It won’t completely prevent man in the middle attacks, but it makes them harder
- Use EE’s input & db libraries instead of raw PHP code to process forms and save data to the db. Be paranoid about any input you get from your API and be extremely narrow what data you’ll accept
- Use CodeIgniter models so your API code can use the same business logic as the rest of your module
- Organize your code into libraries for reusability, move common code for your API into base classes.
Finally here are a few tools to help you debug and test your API:
- JSONLint to validate/test JSON is valid
- Postman is a REST client for Chrome, send & receive HTTP request & responses, very good tool for quick inspection of your API without having to right an app. Although I’d highly recommend learning PHPUnit or SimpleTest and writing real unit tests.
- For Windows there’s Fiddler which is an amazing powerful tool for debugging HTTP requests & responses. It can do security and man-in-the-middle attack tests and has a number of advanced features.
I hope this is enough to get you started in the world of APIs and how you can implement them for your ExpressionEngine add-ons.