Building a Laravel 4 RESTful API - Part 1
Over the last several months I have been building a RESTful API. One of the first challenges I came across was determining the best structure in terms of URI endpoints. The first place I started was doing some research on REST API’s. Like most web developers, I’ve spent a lot of time consuming REST API’s, and love the straight forward simplicity of the structure, but what was the best way to build one? It seems like every service you consume, takes a different approach to organizing and designing end points and responses. The differences between, Facebook, LinkedIn, Twitter and Instagram just for an example are quite different, even though they all share some common functionality. My initial research turned up a book titled REST in Practice by Jim Webber, Savas Parastatidis, and Ian Robinson. If you’re new to designing REST API’s I strongly recommend the book. It does a great job of discussing the different levels of a REST API, and helps you determine which solution is the right one for your particular application. One complaint on the book though is it’s very focused on XML and Atom feeds. Since I prefer JSON I found some of it, especially the focus on ATOM feeds, to be unhelpful.
After my initial research period I’ve decided on relying heavily on HTTP verbs and having resource end points. The verbs I’ll be using are GET, POST, PUT, PATCH, and DELETE. This is going to line up well with a CRUD (Create, Read, Update, and Delete) methodology. For example, let’s say we have a resource called snacks. My end points for snack may look like:
GET:: //mydomain.com/api/v1/snacks - index
GET:: //mydomain.com/api/v1/snacks/1 - show
GET:: //mydomain.com/api/v1/snacks/create – create form
GET:: //mydomain.com/api/v1/snacks/edit – edit form
POST:: //mydomain.com/api/v1/snacks - store (create data in DB)
PUT:: //mydomain.com/api/v1/snacks/1 – update (entire record)
PATCH:: //mydomain.com/api/v1/snacks/1 - update (individual column in record)
DELETE:: //mydomain.com/api/v1/snacks/1 – destroy (removes record from DB)
One thing to note here is the same endpoints are used over and over again. The API should be able to route based on what VERB is being used. You’ll also notice that we have a v1 in the url. There is debate on the best way to track versions for your API’s, and In another article I’ll discuss the versioning API challenge.
The next step in building an API is deciding a framework or language. I program mostly in PHP and JavaScript so my two first choices were Laravel 4.1 or node.js with Express and express-resource. I decided to go with Laravel 4.1 due to my familiarity with Laravel, and the simplicity in building resource controllers.
If you’re a PHP developer and haven’t used Laravel yet you need to check this framework out. It’s a very powerful framework and also encourages using stronger application architecture with a large focus on testability and decoupling. It also uses composer which is a much-needed tool to simplify package management in PHP.
Now that we have our planning phase and research phase mostly done (not that it ever really ends), let’s start looking at some actual code.
First download laravel, and get it setup. For step-by-step instructions, I’m going to recommend the laravel getting started documentation, which can be found here: http://laravel.com/docs/installation
Once you have your laravel installation created, let’s get started by creating a resource controller. Laravel has this great command line tool called artisan. We’re going to use that to create our resources.
php artisan controller::make SnackController
You should now see SnackController in your app/controller directory. However, before we can use it; we need to register the routes for it. Laravel takes care of creating all the routes we had specified above with one line of code in our routes.php
file.
Route::resource(‘snacks’, ‘SnackController’);
Now all the end points we had outlined above will be grabbed and directed to our resource controller. The controller already has methods created that match up with the names we gave the endpoints earlier. One thing you should note though is that PUT/PATCH both hit the update method in your controller. If you want to separate functionality based on the verb you’ll have to determine the verb in your update method. You can find that verb in Laravel with Request::isMethod('patch')
.
Now we have our Laravel application setup, we have a snacks resource, and we have our routes registered. We now need to create a database for it. Laravel has a great DB management tool built in called Migrations. You can use Migrations to create your DB structure. This also allows you to ‘roll’ back changes to the DB if you manage your DB structure entirely in Laravel migrations. I haven’t quite drunk the cool aid on Migrations so I just created a snacks table. My snacks table looks like:
CREATE TABLE `snacks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(145) NOT NULL,
`description` varchar(255) NOT NULL,
`active` tinyint(4) NOT NULL DEFAULT '1',
`deleted_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1$$
In Laravel I use the Eloquent ORM which is a simple ActiveRecord implementation. I highly recommend using it but you can also use the Query Builder which gives you a bit more control over constructing your SQL statements. Either way, Laravel will manage created_at
, updated_at
timstamps for you. Also, you can enable a feature called soft delete by adding a column called deleted_at
and enabling the feature in your Eloquent models. This feature will only retrieve records whose deleted_at column is equal to null. Another nice feature is Query Builder, and Eloquent uses PDO parameter binding throughout to protect against SQL injection.
Now that we have a table, we’ll need to jump into app/config/database.php
and make sure our database is configured correctly. Once we have done that, we’ll need to visit app/models/
and create a new model for our database table. These models allow us to use the Eloquent ORM to work with our database tables very easily.
Here’s an example of what our Snacks Model might look like:
<?php
class Snack extends Eloquent{
/**
* The database table used by the model.
* @var string
*/
protected $table = 'snacks';
/**
* Enable/Disable $softDelete: Disabled by
* default.
* @var boolean
*/
protected $softDelete = true;
}
Note: Your table name should be the plural of the resource, and the class name should not be plural, but the singular version of your resource's name.
Now we are ready to drop some code into our SnacksController. For simplicity let’s add this code to our index method:
Return json_encode(Snack::all());
Now before we can get any results, we need to populate the DB. I use MYSQL workbench, but you can do this however you want including with migrations. Once you have populated some data into your table, you can open your browser and go to your site
//mydomain.com/snacks
You should see the results of your snacks table wrapped in json.
This of course isn’t wrapping the responses in HTTP codes, but we’ll get to that in another article.
But for now, you are well on your way to creating a REST API. Try this out with some JavaScript Ajax to get a sense of what’s going on. Also, I encourage you to continue studying the Laravel documentation and work on building out the rest of your Snack endpoints.
Next article we’ll discuss wrapping responses in HTTP codes, and version control.