Home » Php » How to make a REST API first web application in Laravel

How to make a REST API first web application in Laravel

Posted by: admin November 30, 2017 Leave a comment

Questions:

I want to make an API first application in Laravel. I don’t know what is the best approach to do this, I will explain what I am trying to do, but please feel free to give answers how to do this in a different way.

I don’t want all my frontend to be written in javascript and parse the JSON output of the API with angular.js or something similar. I want my Laravel application to produce the HTML views. I am trying to go down the road of having two controllers one on for the API and one for the web. For the show User action my routes.php looks like this:

# the web controller
Route::controller('user', 'WebUserController');

# the api controller 
Route::group(array('prefix' => 'api'), function() {
    Route::resource('user', 'UserController');
});

So /user will take me to WebUserController and /api/user will take me to the UserController. Now I want to put all my logic in the API UserController, and call its actions from the WebUserController. Here is the code for both of them:

class UserController extends BaseController 
{
    public function show($id)
    {
        $user = User::find($id);
        return Response::json(array('success'=>true,'user'=>$user->toArray()));
    }
}

class WebUserController extends UserController 
{
    public function getView($id) 
    {
         # call the show method of the API's User Controller
         $response =  $this->show($id);
         return View::make('user.view')->with('data', $response->getData());
    }
}

In the WebUserController I am able to get the json content of the response with getData(), but I am not able to get the headers and status code (they are protected properties of Illuminate\Http\JsonResponse).

I think that my approach might not be the best, so I am open to suggestions how to make this app.

EDIT: The question how to get the headers and status of the response has been answered by Drew Lewis, but I still think that there might be a better way how to design this

Answers:

You should utilize the Repository / Gateway design pattern: please see the answers here.

For example, when dealing with the User model, first create a User Repository. The only responsibility of the user repository is to communicate with the database (performing CRUD operations). This User Repository extends a common base repository and implements an interface containing all methods you require:

class EloquentUserRepository extends BaseRepository implements UserRepository
{
    public function __construct(User $user) {
        $this->user = $user;
    }


    public function all() {
        return $this->user->all();
    }

    public function get($id){}

    public function create(array $data){}

    public function update(array $data){}

    public function delete($id){}

    // Any other methods you need go here (getRecent, deleteWhere, etc)

}

Then, create a service provider, which binds your user repository interface to your eloquent user repository. Whenever you require the user repository (by resolving it through the IoC container or injecting the dependency in the constructor), Laravel automatically gives you an instance of the Eloquent user repository you just created. This is so that, if you change ORMs to something other than eloquent, you can simply change this service provider and no other changes to your codebase are required:

use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider {

    public function register() {
        $this->app->bind(
            'lib\Repositories\UserRepository',        // Assuming you used these
            'lib\Repositories\EloquentUserRepository' // namespaces
        );
    }

}

Next, create a User Gateway, who’s purpose is to talk to any number of repositories and perform any business logic of your application:

use lib\Repositories\UserRepository;

class UserGateway {

    protected $userRepository;

    public function __construct(UserRepository $userRepository) {
        $this->userRepository = $userRepository;
    }

        public function createUser(array $input)
        {
            // perform any sort of validation first
            return $this->userRepository->create($input);
        }

}

Finally, create your User web controller. This controller talks to your User Gateway:

class UserController extends BaseController 
{
    public function __construct(UserGatway $userGateway)
    {
        $this->userGateway = $userGateway;
    }

    public function create()
    {
        $user = $this->userGateway->createUser(Input::all());

    }
}

By structuring the design of your application in this way, you get several benefits: you achieve a very clear separation of concerns, since your application will be adhering to the Single Responsibility Principle (by separating your business logic from your database logic) . This enables you to perform unit and integration testing in a much easier manner, makes your controllers as slim as possible, as well as allowing you to easily swap out Eloquent for any other database if you desire in the future.

For example, if changing from Eloquent to Mongo, the only things you need to change are the service provider binding as well as creating a MongoUserRepository which implements the UserRepository interface. This is because the repository is the only thing talking to your database – it has no knowledge of anything else. Therefore, the new MongoUserRepository might look something like:

class MongoUserRepository extends BaseRepository implements UserRepository
{
    public function __construct(MongoUser $user) {
        $this->user = $user;
    }


    public function all() {
        // Retrieve all users from the mongo db
    }

    ...

}

And the service provider will now bind the UserRepository interface to the new MongoUserRepository:

 $this->app->bind(
        'lib\Repositories\UserRepository',       
        'lib\Repositories\MongoUserRepository'
);

Throughout all your gateways you have been referencing the UserRepository, so by making this change you’re essentially telling Laravel to use the new MongoUserRepository instead of the older Eloquent one. No other changes are required.

Questions:
Answers:

You should be use Repository for this design.

Example –

//UserRepository Class
class UserRepository {
    public function getById($id)
    {
      return User::find($id);
    }
}

// WebUser Controller
class WebUserController extends BaseController {
    protected $user;

    public function __construct(UserRepository $user)
    {
        $this->user = $user;
    }

    public function show($id)
    {
        return View::make('user.view')->with('data', $this->user->getById($id));
    }
}

// APIUser Controller
class UserController extends BaseController {
    protected $user;

    public function __construct(UserRepository $user)
    {
        $this->user = $user;
    }

    public function show($id)
    {
        $data =>$this->user->getById($id);
        return Response::json(array('success'=>true,'user'= $data->toArray()));
    }
}

Questions:
Answers:

Checkout Laravel’s RESTful controllers:

http://laravel.com/docs/controllers#restful-controllers

Their docs do a pretty good job.

But even better is this tutorial:

http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated–net-29785

Questions:
Answers:

This is a video by Jeffrey Way he is one of the better Laravel developers. In this tutorial he is connecting a BackboneJS application to a RESTful service that he sets up in Laravel. It doesn’t get any better then this. I can write you a lot of boilerplate, but just learn it by watching a nice video and having a coffee. 😉

https://www.youtube.com/watch?v=uykzCfu1RiQ

Questions:
Answers:

I have a response to the problem you are having with the Response.
You can get the headers, status code and data from the Response.

// your data
$response->getData();

// the status code of the Response
$response->getStatusCode(); 

// array of headers
$response->headers->all();

// array of headers with preserved case
$response->headers->allPreserveCase(); 

$response->headers is a Symfony\Component\HttpFoundation\ResponseHeaderBag which inherits from Symfony\Component\HttpFoundation\HeaderBag

Questions:
Answers:

I would also recommend using a repository.
Attempting to call one controller from another would be falling into a pattern called HMVC (Hierarchical model–view–controller).
This means that your entire application relies on lower modules.
In this case, your API would serve as a repository for your data (which isn’t the worst thing in the world at first).

However, when you then modify the structure of how data is returned in your API, everything else relying on it would have to know how to respond.
Say you wanted to have authorization checks to see if a logged in user should be able to see the details of a returned user and there was an error.

In the API, you would return a Response object with a 403 forbidden code and some meta data.
Your HTML controller would have to know how to handle this.

Contrast this to a repository which could throw an exception.

public function findById ($id)
{
    $user = User::findOrFail($id);

    if (Auth::user->hasAccessTo($user)) {
        return $user;
    } else {
        throw new UnauthorizedAccessException('you do not have sufficient access to this resource');
    }
}

And your API controller would look more like this:

public function show($id)
{
    try {
        return $this->user->findById($id);
    } catch (UnauthorizedAccessException $e) {
        $message = $e->getMessage();
        return Response::json('403', ['meta' => ['message' => $message]]));
    }
}

Your HTML controller would then look like this:

public function show($id)
{
    try {
        $user = $this->user->findById($id);
    } catch (UnauthorizedAccessException $e) {
        Session::flash('error', $e->getMessage());
        // Redirect wherever you would like
        return Response::redirect('/');
    }
}

This gives you very reusable code and let’s you change your controller implementations independently without worry of changing the other’s behavior.
I wrote more on how to implement the repository pattern in this post: you can ignore the interface and skip right to the implementations if you would like.