The Todo app contains a task list that will gonna perform on a daily basis or specified time frame. For creating any task, we will require login into the application. So, the application will contain the user registration and login. For the authentication, I will be using the passport auth in the Laravel 7. I had already shared some post on the RESTful APIs in the Laravel 7. So, if you are an absolute beginner in the RESTful API then I recommend you go through that post for more clarity. Users can create multiple tasks. But, the created tasks will be displayed to that user only who is created. Also, without login, no one can create and view the task. So, let’s create a new project in Laravel 7.
Prerequisites
I assume your system is ready to create a new Laravel 7 project. If not then make ready with the below tools.
- PHP >= 7.2.5
- MySQL > 5
- Apache/Nginx Server
- Composer
- Postman
Create a Laravel 7 Project For Todo App
I will be trying to cover all the necessary steps so that you will not miss any steps here. Open the terminal and create the project by giving a name. I have given the project name to-do-app.
composer create-project --prefer-dist laravel/laravel to-do-app
It will take a couple of minutes to create the project.
After creating the project, let’s create and configure the database.
Create and Configure Database for ToDo App
Create a database in MySQL and configure it in the project.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_todo
DB_USERNAME={{-- YOUR DB USERNAME --}}
DB_PASSWORD={{-- YOUR DB PASSWORD --}}
Install Passport Package in Laravel 7 For Todo App
In this step, we will be installing the passport package for the authentication for the Todo App REST API. So, for this, we will require to add the package inside our project.
composer require laravel/passport
In the terminal, type the above command to install the package. Just wait while the package will be adding in the project.
Laravel 7 Upload Multiple Images with Image Validation
So, here package has been added for the Todo App REST API. You can check it in the composer.json file present in the root the project directory. Now, it’s good to go for the next step.
Create Models and Migrations
For our application, it will require to work on the Users and Task module for the Todo app API. So, the todo app will require two models and migrations. The models and migrations will be for the User and for the Task. In Laravel, it provides a default model and migration for the user. Hence, we will require only one to create. That is for the task. So, let’s create a model and migration for the task.
php artisan make:model Task -m
Model and migration have been created. Now, let’s do some changes in the migration so that we can configure the exact columns.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('first_name');
$table->string('last_name');
$table->string('full_name');
$table->string('phone');
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
Now, let’s configure the task migration file.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTasksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('task_title');
$table->string('description');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tasks');
}
}
Add Mass Assignment For Fillable Data
So, for the User model, we have the following fillable data as per the migration fields.
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'first_name', 'last_name', 'full_name', 'phone', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Similarly, for the Task table, we will have the fillable data as showing below.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
protected $fillable = [
'task_title', 'description', 'user_id'
];
}
Now, we will create a relation between the User and Task Model. So, that it can relate to each other.
Create Relation Between Task and User Model
Laravel eloquent makes ease to define the relationships among the models. We need only to define the relationship so that it can relate the fields and can manage easily. So, here we have the User and Task model. Hence, the relation between both the table is one-to-many. Actually, the user can create single as well as multiple tasks. Similarly, multiple tasks can be created by multiple users.
Therefore, we will create a method inside the User model to define the relation of Task.
public function task()
{
return $this->hasMany('App\Task');
}
After adding the above function the user model will look as showing below.
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'first_name', 'last_name', 'full_name', 'phone', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function task()
{
return $this->hasMany('App\Task');
}
}
Now, we will migrate the database.
Migrate Schema of Todo App Database
In this step, we will migrate the tables into the database. So, in this migration process, all the tables will be migrated into the database.
php artisan migrate
Here, the migration has been completed successfully.
In the next step, we will be adding the Auth Guard in the Auth service provider. This will filter out the API request.
Add Auth Guard in Auth Service Provider
You will find out the Auth Service Provider inside the app/Providers. Before setting the passport route, just add the below namespace at the top.
use Laravel\Passport\Passport;
After using the above namespace, we will add a route inside the boot() function. Here, the class will look like this.
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
Now, we will be adding the auth guards for the API Requests. You will find the auth.php inside the config file. So, just change the below driver for the API. Hence, we are using the Passport so replace the API driver with passport.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
In the next step, we will be adding the passport auth to the table. It will install the auth key for validating the users. Laravel passport provides the OAuthClients and OAuthPersonalAccessClient for the encryption key. The encryption key will be helpful to validate the API request of the authenticated user.
Now, we are ready to create the Laravel 7 Todo app REST API. Therefore, we will create the controllers and routes respectively.
Create Controllers For Laravel 7 Todo App REST API
For the Todo App, we will require two controllers. As we have created models and the migrations.
- User Controller
- Task Controller
So, let’s create one by one. Then we will proceed to the functionalities of creating the Todo App REST API.
php artisan make:controller UserController
php artisan make:controller TaskController
Now, we have the User and Task controller. Therefore, let’s create the functionalities of Todo app.
Firstly, we will create the API for the user sign up and login.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\User;
class UserController extends Controller
{
private $sucess_status = 200;
// ------------- [ User Sign Up ] ---------------
public function createUser(Request $request) {
$validator = Validator::make($request->all(),
[
'first_name' => 'required',
'last_name' => 'required',
'phone' => 'required|numeric',
'email' => 'required|email',
'password' => 'required|alpha_num|min:5'
]
);
if($validator->fails()) {
return response()->json(["validation_errors" => $validator->errors()]);
}
$dataArray = array(
"first_name" => $request->first_name,
"last_name" => $request->last_name,
"full_name" => $request->first_name . " " . $request->last_name,
"phone" => $request->phone,
"email" => $request->email,
"password" => bcrypt($request->password),
);
$user = User::create($dataArray);
if(!is_null($user)) {
return response()->json(["status" => $this->sucess_status, "success" => true, "data" => $user]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! user not created. please try again."]);
}
}
// ------------------- [ User Login ] ----------------
public function userLogin(Request $request) {
$validator = Validator::make($request->all(),
[
'email' => 'required|email',
'password' => 'required|alpha_num|min:5'
]
);
if($validator->fails()) {
return response()->json(["validation_errors" => $validator->errors()]);
}
if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
$user = Auth::user();
$token = $user->createToken('token')->accessToken;
return response()->json(["status" => $this->sucess_status, "success" => true, "login" => true, "token" => $token, "data" => $user]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! invalid email or password"]);
}
}
// ------------------ [ User Detail ] ------------------
public function userDetail() {
$user = Auth::user();
if(!is_null($user)) {
return response()->json(["status" => $this->sucess_status, "success" => true, "user" => $user]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! no user found"]);
}
}
}
In the above functions, we have the user sign up, login, and user detail. I have used the validator class to validate the input fields. Through the createUser() function, the user can sign up for the new account. In the userLogin() function a token will be created.
We are done with the UserController here. To call these functions, we will need to create the routes.
Add Routes for UserController
I am going to add these three routes in the routes/api.php.
Route::post("create-user", "UserController@createUser");
Route::post("user-login", "UserController@userLogin");
Route::group(['middleware' => 'auth:api'], function () {
Route::get("user-detail", "UserController@userDetail");
});
Now, run the application to check whether these functionalities are working perfectly or not. For testing the APIs, I will be using the Postman.
For creating a new user this will be the endpoint.
http://localhost:8000/api/create-user
Request Type: POST
Firstly, I will be showing the validation that we have set for the forms. Here, I have kept form fields to empty and hit the endpoint for creating a new user.
In the response of the empty form fields, it will be showing the validation error message.
Now try with filling up the required fields in the body/form-data.
So, after filling up the form fields, when you will hit the API, it will return the response as showing below.
Now, similarly for the user login the endpoint will be –
http://localhost:8000/api/user-login
Request Type: POST
For the user login the required fields are email and password. Therefore, if you will leave it empty then it will show you the validation errors message as showing below.
When you will fill up the required fields like email and password then it will show the response.
This is the response of successful login with the authentication token.
There is one more endpoint for the UserController. That is for the user detail.
localhost:8000/api/user-detail
Request Type: GET
The user detail endpoint will require the authorization as a token in the header. Because, I have passed the route in the middleware of auth.
The auth route group will require the token in the header. After hitting the API, you will get the response like below.
That’s it for the UserController. Now, let’s move to the TaskController.
Create Functionality For TaskController
Add the below snippet in the TaskController.php file.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Task;
class TaskController extends Controller
{
private $sucess_status = 200;
// --------------- [ Create Task ] ------------------
public function createTask(Request $request) {
$user = Auth::user();
$validator = Validator::make($request->all(),
[
"task_title" => "required",
"description" => "required",
]
);
if($validator->fails()) {
return response()->json(["validation_errors" => $validator->errors()]);
}
$task_array = array(
"task_title" => $request->task_title,
"description" => $request->description,
"status" => $request->status,
"user_id" => $user->id
);
$task_id = $request->task_id;
if($task_id != "") {
$task_status = Task::where("id", $task_id)->update($task_array);
if($task_status == 1) {
return response()->json(["status" => $this->sucess_status, "success" => true, "message" => "Todo updated successfully", "data" => $task_array]);
}
else {
return response()->json(["status" => $this->sucess_status, "success" => true, "message" => "Todo not updated"]);
}
}
$task = Task::create($task_array);
if(!is_null($task)) {
return response()->json(["status" => $this->sucess_status, "success" => true, "data" => $task]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! task not created."]);
}
}
// ---------------- [ Task Listing ] -----------------
public function tasks() {
$tasks = array();
$user = Auth::user();
$tasks = Task::where("user_id", $user->id)->get();
if(count($tasks) > 0) {
return response()->json(["status" => $this->sucess_status, "success" => true, "count" => count($tasks), "data" => $tasks]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! no todo found"]);
}
}
// ------------------ [ Task Detail ] -------------------
public function task($task_id) {
if($task_id == 'undefined' || $task_id == "") {
return response()->json(["status" => "failed", "success" => false, "message" => "Alert! enter the task id"]);
}
$task = Task::find($task_id);
if(!is_null($task)) {
return response()->json(["status" => $this->sucess_status, "success" => true, "data" => $task]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! no todo found"]);
}
}
// ----------------- [ Delete Task ] -------------------
public function deleteTask($task_id) {
if($task_id == 'undefined' || $task_id == "") {
return response()->json(["status" => "failed", "success" => false, "message" => "Alert! enter the task id"]);
}
$task = Task::find($task_id);
if(!is_null($task)) {
$delete_status = Task::where("id", $task_id)->delete();
if($delete_status == 1) {
return response()->json(["status" => $this->sucess_status, "success" => true, "message" => "Success! todo deleted"]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Alert! todo not deleted"]);
}
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Alert! todo not found"]);
}
}
}
In the above snippet, we have the functionality to create/update task. task listing, task detail and delete task.
For the above functions, we will add the routes in the middleware. The APIs inside the middleware would require the bearer token.
Add Routes For Todo App
Here are the routes for both controllers which are UserController and the TaskController.
Route::post("create-user", "UserController@createUser");
Route::post("user-login", "UserController@userLogin");
Route::group(['middleware' => 'auth:api'], function () {
Route::get("user-detail", "UserController@userDetail");
Route::post("create-task", "TaskController@createTask");
Route::get("tasks", "TaskController@tasks");
Route::get("task/{task_id}", "TaskController@task");
Route::delete("task/{task_id}", "TaskController@deleteTask");
});
So, let’s go through one by one.
Create/Update Task
This is the endpoint for creating/updating a task.
localhost:8000/api/create-task
Request Type: POST
You will have to pass the auth token in the header as showing below.
Now, in the form body, pass the parameters of form fields.
After that hit the API to get the response.
For updating the task, you will have to pass one more field through which the task will be updating. So, the primary field is id. Hence, we will have to pass the id of the task in the form fields.
Also, you will have to pass the authorization like previously done. Change the value that you want to update. And the result will be like same as showing.
Tasks Listing
For the task listing we have the endpoint.
localhost:8000/api/tasks
Request Type: GET
Pass the authorization token for the task listing. So, that the task will be listed out of current logged user.
Here, the tasks has been listed of current logged user.
Task Detail
Similarly, for the task detail, here is the endpoint.
localhost:8000/api/task/1
Request Type: GET
Again pass the authorization token. Also, in this endpoint you will have to pass the task id that you want to see.
In the response, you will get the todo of entered id.
Delete Task
For deleting the task, we have the endpoint with delete request. This will take task id as a parameter.
localhost:8000/api/task/3
Request Type: DELETE
Also, you will have to pass the header authorization. Because, no one can delete the task created by the other user.
Conclusion
We have implemented passport authentication successfully in the RESTful APIs. So, here the APIs for the todo app has been created. You can extend its functionalities as per your requirement. This is just a demonstration of the todo app. Now, the APIs are ready to use in any front-end technology like React, Vue, and Angular, etc. I will be using this API in the React post and will implement it for the React todo app. So, stay connected with us for the next post. I hope this will help you out to create any APIs with the bearer token using the OAuth2.
Ab says
how do you go about testing the route on postman. can’t it be possible to test with the browser console.
Umesh Rana says
You can test the GET request API in the browser. But for the POST request, where you will have to pass the form input data will require any tools or browser extension.