Building RESTful API in Laravel – part 2 – Design API Controller

In the previous tutorial (https://maxoffsky.com/code-blog/building-restful-api-in-laravel-start-here/) I shared the basics of RESTful controller structure and a route that we will need to build a RESTful web application. As promised, in this tutorial we will explore how exactly to make our API work with our data.

We will explore a simple Todo list application as and example.

Let’s start with a simple structure for the Todo database. I am using MySQL but you can use whatever DB you are comfortable with, just make sure Laravel supports it.

Our Todo items will have id, title (name of the todo), completed (yes or no) and timestamps.

Create a new DB called “apitest” and run this SQL query to create necessary fields :

CREATE TABLE `todos` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `completed` varchar(4) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Make sure you update your application/config/database.php file with the name of your DB and credentials.

Alright, we have a clean DB, now let’s make a Laravel model so that it’s aware of DB structure.

Create a file called todo.php in your application/models. Copy/paste the following :

<?php

   class Todo extends Eloquent {

   }

?>

That’s it for the model!

Let’s go back to our controller structure from the previous tutorial and fill it up with meaningful actions on the model.

Before that, let’s think about it for a minute, what should we be able to do with our data?

We need to receive our data about a todo as a JSON string of data, for example like this :

{"id":"1","title":"First todo","completed":"no","created_at":"2012-11-16 22:22:53","updated_at":"2012-11-16 22:23:07"}

Laravel has amazing Eloquent methods of working with data, and we will be using some of that potential to make our app do what we want it to do. There is one feature of Laravel that people sometimes miss, Returning Eloquent models as JSON responses, as documented in the docs: http://laravel.com/docs/views.

This means we could do something like this in our controller :

return Response::eloquent(Todo::find(1));

And we will get exactly what we want – a Todo item with id 1, that will look like the one JSON string above.

Awesome, isn’t it?

Let’s sketch the algorithm and flow of our application, analyzing each action in enough detail to get a vision of our TODO API:

GET index (ID) should return all Todos in JSON encoded format if there is no ID present, otherwise return JSON encoded object of the todo with ID.

POST index should get our JSON input and create a new todo and save it to the database. We can return the JSON-inified new todo back to our application to acknowledge creation of new object.

PUT index should receive input that contains an ID, “title” and “completed” data, then check if the todo with ID exists, then updated that todo with the new data.

DELETE index (ID) should receive ID as a parameter, find a todo with that ID and delete it if it exists, otherwise return an error.

Simple enough? Let’s code our controller right away then!

<?php

class Api_Todos_Controller extends Base_Controller {

	public $restful = true;

	public function get_index($id = null) 
	{
		if (is_null($id )) 
		{
			return Response::eloquent(Todo::all());
		} 
		else 
		{
			$todo = Todo::find($id);

			if(is_null($todo)){
			    return Response::json('Todo not found', 404);
			} else {
	        	    return Response::eloquent($todo);
			}
		}
	}

	public function post_index() 
	{

		$newtodo = Input::json();

		$todo = new Todo();
		$todo->title = $newtodo->title;
		$todo->completed = $newtodo->completed;
		$todo->save();

		return Response::eloquent($todo);
	}

	public function put_index() 
	{
		$updatetodo = Input::json();

		$todo = Todo::find($updatetodo->id);
		if(is_null($todo)){
		    return Response::json('Todo not found', 404);
		}
		$todo->title = $updatetodo->title;
		$todo->completed = $updatetodo->completed;
		$todo->save();
		return Response::eloquent($todo);
    }

    public function delete_index($id = null) 
    {
		$todo = Todo::find($id);

		if(is_null($todo))
		{
		     return Response::json('Todo not found', 404);
		}
		$deletedtodo = $todo;
		$todo->delete();     
		return Response::eloquent($deletedtodo);   
    } 

}

?>

That’s it! We are done with our API part, now let’s test it.

Go to the root of your application in the browser, you should see a default “Laravel installed” page, now go to your API route (the one we specified in routes.php):

api/v1/todos/

and you should see an empty JS array : []

If there is some kind of error, you need to troubleshoot it until you get an empty JS array on your API page.

Now launch your terminal if you are on Mac OS, and do simple CURL commands to see if the API is working. On my machine I execute the following commands and see the following output(replace “apitest/public” with URL to your app):

curl -H “Accept: application/json” -H “Content-type: application/json” -X GET http://localhost/apitest/public/api/v1/todos/

Output : [].

curl -H “Accept: application/json” -H “Content-type: application/json” -X POST -d ‘{“title”:”My First TODO”,”completed”:”no”}’ http://localhost/apitest/public/api/v1/todos/

Output: {“title”:”My First TODO”,”completed”:”no”,”updated_at”:{“date”:”2012-11-16 23:15:18″,”timezone_type”:3,”timezone”:”UTC”},”created_at”:{“date”:”2012-11-16 23:15:18″,”timezone_type”:3,”timezone”:”UTC”},”id”:1}

curl -H “Accept: application/json” -H “Content-type: application/json” -X PUT -d ‘{“id”:”1″,”title”:”MODIFIED My First TODO”,”completed”:”yes”}’ http://localhost/apitest/public/api/v1/todos/

{“id”:”1″,”title”:”MODIFIED My First TODO”,”completed”:”yes”,”created_at”:”2012-11-16 23:15:18″,”updated_at”:{“date”:”2012-11-16 23:18:29″,”timezone_type”:3,”timezone”:”UTC”}}

curl -H “Accept: application/json” -H “Content-type: application/json” -X DELETE http://localhost/apitest/public/api/v1/todos/1

Did it work? If yes, you are good to go, your API is now complete. You can play with it from the command line, but what fun is that?

In the next tutorial we will adapt TodoMVC Backbone application to our Laravel PHP API!

Stay tuned and subscribe to this blog via RSS or follow me on Twitter!

Update! Next part of the tutorial is published:
Building RESTful API in Laravel – part 3 – Integration with BackboneJS

Liked it? Take a second to support Maks Surguy on Patreon!
Become a patron at Patreon!

You may also like

20 comments

  • John Kevin M. Basco November 17, 2012  

    This is great Maks. Thanks a ton for this. Didn’t know that you can get the something from the dbase and return it as json using 1 line of code Response::eloquent(). This is very useful to me since I’m planning to make a mobile app that is using a web api for my thesis 🙂 Thanks again.

  • Dalibor Sojic January 13, 2013  

    Nice tutorial, but I have problem accessing query string parameters. Input::get(‘something’) doesn’t work.

    By the way, laravel still has bugs. Ex:
    domain.com/api/test?x=4
    URI::full() respond with domain.com/api/test?/api/test

  • Steven Bullen January 25, 2013  

    Hi. Great tutorial by the way.

    I maybe wrong; just started with Laravel in the last day or two.

    But if you have a database with a table called todos shouldn’t this line
    class Todo extends Eloquent
    be
    class Todos extends Eloquent
    or of course you could add the following to the model instead.
    public static $table = ‘todos’;

  • Maks Surguy January 31, 2013  

    This is actually just plain PHP question.
    The name of the class and the name of the file should be the same.
    Todo.php should have Todo class.

  • Daniel February 14, 2013  

    Nice tutorial. But how would you best handle app keys (id and secret) the best way in Laravel? With som kind of filter maybe?

  • Maks Surguy February 14, 2013  

    Yes, I think a “before” filter could easily process that data. To make this properly you would need to extend the Auth class with your own (as it is a method of Authentification) and then use that in the filter to your routes.

  • Premke February 24, 2013  

    Maks, just a little tip, instead of writing raw SQL query for creating database structure you should use laravel migrations (http://laravel.com/docs/database/migrations) and schema builder (http://laravel.com/docs/database/schema).

    Rest is great, thanks for tutorial.

  • Maks Surguy February 24, 2013  

    Thank you! Will use this in next tutorials but in this one I needed to focus on other things, the migrations would take more time to demonstrate and add to the tutorial…

  • MGMT March 6, 2013  

    Nice tutorial! I found a nice little overview with best practices for building APIs:
    http://www.startupcto.com/backend-tech/building-an-api-best-practices

    My Question is: How could you generate this JSON envelope easily with Laravel?

    Best
    Andi

  • Maks Surguy March 6, 2013  

    You can easily pass your models through this :
    Returning Eloquent models as JSON:

    return Response::eloquent(User::find(1));

    Or use Response::json($data);

    Here is a good docs part for that :
    http://laravel.com/docs/views

  • seyhman tunç March 8, 2013  

    thank you , clear and perfect tutorial

  • Ranjit April 13, 2013  

    Nice

  • Adrian Barabino May 18, 2013  

    Really excellent tutorial !! With this i now use the backend of my website only for make JSON (for use with Ajax Calls)

    Thanks, one question, i can translate this to Spanish for post on my blog (with the link of this post) ¿?

  • Maks Surguy May 20, 2013  

    Yes I give you my permission to translate this post into Spanish with a link to this blog =)
    Glad it is useful!

  • Alex June 13, 2013  

    Trivial correction: your controller on line 20 needs a semicolon. Great tut.

  • Maks Surguy June 14, 2013  

    Thanks! Updated!

  • Elmasry March 1, 2014  

    Thanks for the great tutorial. Is this secure enough?

  • Maks Surguy March 8, 2014  

    What do you mean secure enough?

Leave a comment