Consuming your Laravel API with JavaScript

Last updated

Antonio Ufano avatar

Antonio Ufano

In one of my recent projects I decided I wanted to build a completely new front end, going from multiple pages to a single page application built with Vue.js. My multi pages web app was using different controllers to handle different requests for each resource and, to be honest, was a little messy (duplicated code in different controllers, very similar methods that do similar actions...). Building a SPA meant that I'd have to create an API to handle all the requests so this was a perfect opportunity to do a cleanup and organise my controllers and methods.

Another requirement was that I wanted to keep a session as I had in the multi pages app (using the built in Laravel Auth) but in addition I needed to manage tokens for the API requests. After reading a ton of articles and spending some hours coding different solutions I build a solution to generate the tokens (you can check the last part of this article I wrote), but it had some gaps:

  • I had different login controllers for the web application and for the application that consumed the API. The web one created a session and the API one generated a token.
  • I wasn't sure how to store the token in a session.
  • If the user didn't manually sign off, the token was kept in the database until the next login.

Then after some more investigation I found a small section in the Laravel Passport documentation for consuming your API with Javascript. This section is part of the whole Passport documentation, that guides you to create a OAuth2 server to emit client and personal tokens which was too overkill for what I needed. So after some tests checking which parts of the whole guide were really needed and which weren't I came up with the following guide.

Note: you can find all the code of this guide in the following GitHub repository

How to consume your Laravel API with Javascript

NOTE: I'm not going to explain what some of the basic commands do when creating a Laravel app as there are plenty of guides out there.

Lets assume you don't even have a Laravel application. Create it using the CLI:

$laravel new demo-passport

Now we have to configure our application to access our database. We do this in the .env file:

DB_DATABASE=database_name
DB_USERNAME=database_user
DB_PASSWORD=database_password

Create the web authentication components with:

$php artisan make:auth

$php artisan migrate

As we're going to use Passport to generate and handle the tokens we need to add passport to our project:

$composer require laravel/passport

Once all Passport files are downloaded and our database is configured we have to install. The install command will also generate a couple of keys in our storage folder.

$php artisan passport:install

Now we need to modify our User model (app/User.php file) and add the HasApiToken trait:

//for API authentication with Passport

use Laravel\Passport\HasApiTokens;

class User extends Authenticatable

{

    use HasApiTokens, Notifiable;

    .......

}

Next we have to configure our /config/auth.php to indicate our app to use passport as our driver for API requests:

'guards' => [

    'web' => [

        'driver' => 'session',

        'provider' => 'users',

    ],

    'api' => [

        //for API authentication with Passport

        'driver' => 'passport',

        'provider' => 'users',

    ],

],

The next thing to do is to add the createFreshApiToken middleware in our app/Http/Kernel.php. This is the most important step as this middleware indicates our app to generate an API token and include it in every request:

protected $middlewareGroups = [

    'web' => [

        ................

        //for API authentication with Passport

        \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,

    ],

That's basically all we have to do regarding the Passport configuration. Now we just have to create our Model and Controller to handle the requests to our API. You can find an example in my repo to manage Tasks (Model and Controller).

As with any other Laravel application we have to define the web routes in routes/web.php and the API routes in routes/api.php. Find below some examples with public and login protected routes:

//public web routes

Route::get('/', function () {

  return view('welcome');

});

//Laravel Auth web routes

Auth::routes();

// Auth protected web routes

Route::group(['middleware' => ['web', 'auth']], function () {

  Route::get('home', 'HomeController@index')->name('home');

});

// Auth protected API routes

Route::middleware('auth:api')->group( function(){

  Route::get('/tasks', 'Api\TaskController@index')->name('api.tasks');

  Route::post('/tasks', 'Api\TaskController@store')->name('api.tasks.store');

  Route::post('/tasks/{id}/complete', 'Api\TaskController@complete')->name('api.tasks.complete');

});

If you want to build your front end with Vue.js like me, as it's included by default in Larave you can just run "npm install" to download it. As Passport will take care of handling the authentication, in your Vue components you can consume your API with axios without passing the token explicitly:

      getTasks() {

          axios.get('/api/tasks')

              .then(response => this.tasks = response.data)

      },

You can find an example component in my repository.

In the web controllers I usually retrieve the logged user with Auth::user() but in order to obtain the logged user for an API request, you'll have to use $request->user() so you'll need to receive a Request object in your methods, event in the ones hat handles a GET request. For example, in the routes defined above we're managing a Task resource that belongs to a User. A logged user can retrieve his tasks (GET request), create a new one (POST request) or complete them (POST request too). The controller that will handle these requests will be like this:

  public function index(Request $request){

    //retrieve the different lists of tasks

    $user = $request->user();

    $tasks = $user->tasks()->get();

    //return JSON with both lists

    return response()->json($tasks, Response::HTTP_OK );

  }


  public function store(Request $request){

    //create new task

    $task = new Task;

    //asign values from view

    $task->name = $request->name;

    $task->description = $request->description;

    $task->completed = false;

    //retrieve user with api guard using api_token

    $user = $request->user();

    //associate user to the new task to fill the user_id column in table

    $task->user()->associate($user);

        //save in database

        $task->save();

    //return new task and http code

    return response()->json([$task], Response::HTTP_CREATED );

  }


  public function complete(Request $request, $id){

    //retrieve user with api guard using api_token

    $user = $request->user();

    //check if task id belongs to the same user before completing it

    $task = $user->tasks()->findOrFail($id);

    $task->completed = true;

    $task->save();

    return response()->json('Task completed!', Response::HTTP_OK );

  }

Note that even the index method receives a Request object so we can retrieve the user from it.

Conclusion

As you can see Laravel comes with a build it component to manages not only web authentication but also API authentication. The official documentation for Passport can be a little complex as its mainly focused in creating a OAuth2 server to generate access tokens for other consumers of your API but when you just need to consume your own API, some of the steps are not needed.

Hope you find this article as useful as the notes I took until I made it work were for me. I'm sure this will be my reference for many projects to come :)

I've published a small application in GitHub that you can clone to check all the code.

Happy coding!

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Oh! and don't forget to follow me on Twitter where I share tons of dev tips 🤙

Other articles that might help you

my projects

Apart from writing articles in this blog, I spent most of my time working on my personal projects.

lifeboard.app logo

theLIFEBOARD.app

theLIFEBOARD is a weekly planner that helps people achieve their goals, create new habits and avoid burnout. It encourages you to plan and review each week so you can easily identify ways to improve your productivity while keeping track of your progress.

Sign up
soliditytips.com logo

SolidityTips.com

I'm very interested in blockchain, smart contracts and all the possiblilities chains like Ethereum can bring to the web. SolidityTips is a blog in which I share everything I learn about Solidity and Web3 development.

Check it out if you want to learn Solidity
quicktalks.io logo

Quicktalks.io

Quicktalks is a place where indie hackers, makers, creators and entrepreneurs share their knowledge, ideas, lessons learned, failures and tactics they use to build successfull online products and businesses. It'll contain recorded short interviews with indie makers.

Message me to be part of it