Consuming your Laravel API with JavaScript
Last updated
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.
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 upSolidityTips.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 SolidityQuicktalks.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