Data security in APIs is a crucial challenge in any programming language. If you are creating any APIs for your web application then there might be a risk to access and misuse the APIs. Therefore the authentic request is required for every single call of the API. It will validate all the HTTP requests which are coming from the web. If we talk about API security then most of the programming language and framework use JWT (JSON Web Token). Laravel supports JWT and Passport Auth for the APIs authentication. So, in this post, you will be learning to create RESTful APIs for the basic blog application using the passport auth. If you are already familiar with some kind of APIs creation and security then this post might be interesting for you. So, let’s dive with Laravel 7 RESTful APIs.
Prerequisites
I am going to start with a new setup of Laravel 7. So, that I can cover step by step guide in the detail. But for creating a Laravel 7 project your system must be ready with the following tools with the required version.
- PHP >= 7.2.5
- MySQL > 5
- Apache/Nginx Server
- VS Code Editor (Optional)
- Composer
I will be creating a Laravel project using the composer.
Laravel 7 Setup for RESTful APIs with Passport Auth
You will require to open the command prompt or the terminal for creating a new project in Laravel 7. Enter the below command, it will create a new project folder with name laravel-7-rest-api. Inside the folder, Laravel libraries and dependencies files will be installed.
composer create-project --prefer-dist laravel/laravel laravel-7-rest-api
After the successful creation of the project, we will be installing the Passport auth package inside our project. Laravel provides all the required package for the implementation. We just need to add it inside the project as per our requirement. So, here we required the Passport auth package.
Create a CRUD Application in Laravel 7 with Form Validation
Add Passport Auth Package in Laravel 7
In Laravel, the composer provides all the dependency that we require for creating any application. That’s why the composer is called the dependency manager. You can check the available package inside the Laravel by entering the below command.
composer require
You can see the lists of packages are showing. You can install any according to your project requirements. But, here, I am creating a REST APIs for the blog application using the passport auth. That’s why I will be installing the passport auth.
composer require laravel/passport
Here, I have chosen the passport package. Now, it will install inside my project files.
Laravel 7 Upload Multiple Images with Image Validation
Create and Configure Database
In the next step, we will create a database inside the MySQL. Then this database will need to be configured inside the Laravel 7 project. So, let’s create first.
CREATE DATABASE laravel7_rest_api;
Here, the database is created, now, let’s connect it with our application. For integrating the database in Laravel, navigate to the .env file that is present in the root of the project folder. Then add the database and the other credentials as showing below.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel7_rest_api
DB_USERNAME=root
DB_PASSWORD=root
So, our database has connected with our Laravel 7 application. In the next step, we will move to the Model and the tables. We will create a model and the table associated with this model.
Create Model and Migration
As per this project, we will need to create one more model. Actually, In the Laravel application, there is a Model by default that is User. So, I will create a new Model for the Post. In the database, there will be a posts table that will be created by the migration. So, let’s create it.
php artisan make:model Post --migration
sreen shot 4
The above command will create a Model with the name Post. You can find the Model inside the app folder of the project. There will be a model already named User.php. After creating the Post model there will be two models.
How to Implement Pagination in Laravel 6 with Example
Also, in the database/migrations folder, there will be a migration file for the post table. So, the file name will be create_posts_table.php. Now, open the migration file and add some fields for the table.
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string("post_title")->nullable();
$table->string("slug")->nullable();
$table->string("category")->nullable();
$table->string("author")->nullable();
$table->tinyInteger("status")->nullable()->default(0);
$table->tinyInteger("published")->nullable()->default(0);
$table->tinyInteger("draft")->nullable()->default(0);
$table->timestamps();
});
}
Similarly, I will modify the user migration table that is created by default.
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string("first_name")->nullable();
$table->string("last_name")->nullable();
$table->string('name')->nullable();
$table->string('email')->unique();
$table->string("phone")->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
Now, the table schemas are done. Let’s migrate it so that the tables and columns will be created inside the database.
Migrate Table Schema in Laravel 7
For migrating the schemas of the table need to hit the artisan command. Open the terminal or command prompt and hit the command.
php artisan migrate
The above command will generate the tables inside the database.
Add Fillable Data in Model
We will have to specify the fillable data for the table. So, we have two models.
- User and
- Post
Add Fillable Data For User Model
In the User.php file need to use ApiTokens. So, for this use the namespace.
use Laravel\Passport\HasApiTokens;
Now, we will use the function of the above namespace inside the class 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', 'name', 'email', 'phone', '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',
];
}
Add Fillable Data For Post Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'post_title', 'slug', 'category', 'author', 'published', 'draft'
];
}
How to Resize Image in Laravel 6 Before Upload
Add Auth Guard in Auth Service Provider
For Laravel passport authentication, every API request needs to be check. So, this will be done by the Auth Guard. Laravel provides a file named AuthServiceProvider that can be found inside the app/Providers/AuthServiceProvider. So before adding the auth guard let’s add it inside the service provider.
Just set the passport routes there. But first of all, use the below namespace.
use Laravel\Passport\Passport;
After adding the namespace and routes your file will be looking 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();
}
}
Add Auth Guards
You can find the auth.php inside the config file. Just change the API driver from token to passport.,
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Install Passport Auth in Laravel 7
Laravel 7 requires to install the passport auth after table migrations. In this installation process, it will add the OAuthClients and OAuthPersonalAccessClients inside the table. The encryption key will be added to check the API request. Then by using this encryption key, the API request can be validated.
php artisan passport:install
The above command will install the passport inside the table and the encryption key will be added.
Create Controllers
For Laravel passport authentication we will create the following controllers.
- UserController
- PostController
So, let’s create the controller one by one.
php artisan make:controller UserController
php artisan make:controller PostController
After creating the controllers, we will move to the functionality. Firstly, we’ll start with the user sign up, login and then will move to the blog post.
User Sign Up and Login
In the UserController.php, I have used the Auth, validator facades. The Auth facade is used to create the token for the user. It will generate the token every time when user will log in with email and password.
Firstly, in the createUser() function, I have validated the fields so that the user will enter the proper value. If validation fails, it will return the validation errors. On the successful validation of the fields, it will create the user.
Secondly, in the userLogin() function, the user will enter the email and password. The auth will check automatically if the entered email and password are correct. If user auth is validated, then it will create a token for the user. Now, this token can be used further to access the other APIs related to this user.
Lastly, the userDetail() function has created to get the user detail based on the token.
<?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(),
[
'name' => 'required',
'email' => 'required|email',
'phone' => 'required|numeric',
'password' => 'required|alpha_num|min:5',
'confirm_password' => 'required|same:password'
]
);
if($validator->fails()) {
return response()->json(["validation_errors" => $validator->errors()]);
}
$fullName = explode(" ", $request->name);
$first_name = $fullName[0];
$last_name = "";
if(isset($fullName[1])) {
$last_name = $fullName[1];
}
$dataArray = array(
"first_name" => $first_name,
"last_name" => $last_name,
"name" => $request->name,
"email" => $request->email,
"password" => bcrypt($request->password),
"phone" => $request->phone
);
$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) {
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"]);
}
}
}
Routes For UserController
For the UserController, we will require the routes. So, add the below routes.
Route::post("create-user", "UserController@createUser");
Route::post("user-login", "UserController@userLogin");
Route::group(['middleware' => 'auth:api'], function () {
Route::get("user-detail", "UserController@userDetail");
});
Create User (User Sign Up)
For user sign up the endpoint will be –
http://localhost:8000/api/create-user
The request type will be POST. Now, in the Body select form-data and enter the fields as showing below.
In the above result, you can see that the user has been created successfully.
Similarly, for the user login, the endpoint will be –
http://localhost:8000/api/user-login
and the request type will be the POST. In the Body->form-data, enter the email and password that you have created. Then hit send to get the response.
In the above result, you can see, the API response is a success. Also, you will get the user data with the created token. Now, this data can be used anywhere like to maintain the user session after login into your application.
Create and Manage Blog Post
Once the user’s API has been created, you can proceed to create the blog post. For creating the blog post, we require the author. That’s why I have created the user’s registration API first. That means, the blog post can be created when the user is logged in. For creating the blog post, we require the Authorization as a token of the logged-in user.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
class PostController extends Controller
{
private $success_status = 200;
// ----------------- [ Create/Update Post ] --------------------
public function createPost(Request $request) {
$user = Auth::user();
$validator = Validator::make($request->all(),
[
"post_title" => "required",
"category" => "required",
]
);
if($validator->fails()) {
return response()->json(["status" => "failed", "validation_error" => $validator->errors()]);
}
$post_id = $request->post_id;
$postDataArray = array(
"post_title" => $request->post_title,
"slug" => $this->slugGenerator($request->post_title),
"author" => $user->id,
"category" => $request->category,
"status" => 1,
"published" => 1,
);
// check if post exist and has post id then update
$post = Post::find($post_id);
if(!is_null($post)) {
$update_status = Post::where("id", $post_id)->update($postDataArray);
if($update_status == 1) {
return response()->json(["status" => $this->success_status, "success" => true, "message" => "Post updated successfully", "data" => $post]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! failed to create post"]);
}
}
// else create new
$post = Post::create($postDataArray);
if(!is_null($post)) {
return response()->json(["status" => $this->success_status, "success" => true, "message" => "Post created successfully", "data" => $post]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! failed to create post"]);
}
}
// ----------------- [ Slug Generator ] -----------------------
public function slugGenerator($title) {
$slug = str_replace("", "-", strtolower($title));
$slug = preg_replace("/[^A-Za-z0-9\-]/", "-", $slug);
$slug = preg_replace("/-+$&/", "-", $slug);
return $slug;
}
// ---------------- [ Post listing ] --------------------
public function postListing() {
$posts = Post::all()->where("published", 1)->where("status", 1);
if(count($posts) > 0) {
return response()->json(["status" => $this->success_status, "succcess" => true, "count" => count($posts), "posts" => $posts]);
}
else {
return response()->json(["status" => "failed", "success" => false, "count" => count($posts), "message" => "Whoops! no posts found"]);
}
}
// ----------------- [ Post Detail ] --------------------
public function postDetail($slug) {
$post = Post::where("slug", $slug)->first();
if(!is_null($post)) {
return response()->json(["status" => $this->success_status, "success" => true, "data" => $post]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! no post found"]);
}
}
// ------------------- [ Delete Post ] -------------------
public function deletePost($slug) {
$user = Auth::user();
$post = Post::where("slug", $slug)->where("author", $user->id)->first();
if(!is_null($post)) {
$delete_status = Post::where("id", $post->id)->delete();
if($delete_status == 1) {
return response()->json(["status" => $this->success_status, "success" => true, "message" => "post deleted successfully"]);
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "Whoops! failed to delete the post"]);
}
}
else {
return response()->json(["status" => "failed", "success" => false, "message" => "You are not allowed to delete this post"]);
}
}
}
In the above controller, the first function is for creating and updating the blog post. That means if the post id doesn’t exist then it will be created. Otherwise, it will be updated. I have used a single function for both (insert and update). To update the blog post, we require the post id. That’s it.
The blog post listing function will return all the post which have been published and active. It doesn’t require authorization because the blog post can be searched by anyone.
Authorization is needed only when the user will perform any action such as create, update, and delete. So, that in every action the user can update only own post. Similarly, the user can delete only their own created post.
How to Upload Multiple Images in Laravel 6 with Validation
Add Routes for PostController
The above controller will require the following routes to access the functions. So, just define these routes inside the routes/api.php as you have done previously.
Route::get("post-listing", "PostController@postListing");
Route::get("post-detail/{slug}", "PostController@postDetail");
Route::group(['middleware' => 'auth:api'], function () {
Route::post("create-post", "PostController@createPost");
Route::get("delete-post/{slug}", "PostController@deletePost");
});
So, let’s check with the endpoints of the API one by one.
Create a Blog Post
For creating a blog post, the endpoint will be –
http://localhost:8000/api/create-post
Along with the form fields data, you will require to pass the authorization in the header of the API request.
Authorization Bearer TOKEN_KEY_HERE
After passing the authorization as a bearer token, the post will be created as showing below.
Post Listing
For getting all the blog posts, you no need the token in authorization. Actually, this will gonna global so that every user can see the blog posts.
So, for retrieving all the posts, the end point will be –
http://localhost:8000/api/post-listing
The above endpoint will have the GET request type so that we can fetch all the posts.
In the above result, after hitting the end points, you will be getting all the posts which are published and active.
Similarly, for post detail you no need the API token to access. The detail can be accessed by anyone. Hence, it will be a global access. So, the end point will be –
http://localhost:8000/api/post-detail/post-slug
The request type will be GET, since we are trying to get the single post.
In the above endpoint, I have passed the post slug as a parameter. Now, in the result, you can see I got the post detail of the requested post using the slug.
How to Import CSV File Data in Laravel 6
Update Post
To update the post, we will have the same endpoint that is used for creating the post. That means, if there exists the post id in the form data, then the post will be updated otherwise it will be created as a new one.
So, at this endpoint you will have to pass the authorization in the header with the token. Also, there will be an additional parameter called post id. On the basis of that post id, it will gonna update.
Delete Post
For deleting the post, the API will require the API token in the header. Actually, the post can be deleted by the created author only. No, one can delete someone’s other post. Hence, we will require to check the post author by the current logged in user. If it validates, then the post can be deleted. Otherwise, it won’t allow to delete the post.
So, the endpoint will be –
http://localhost:8000/api/delete-post/slug
The request type will be GET and you will have to pass the Authorization in the header.
As you can see in the above result, as an author of my post, I can delete it. Otherwise, it won’t allow you to delete someone’s other post.
How to Use AJAX in Laravel 6 with ToDo Application
Conclusion
I hope you will have the much understanding on creating a RESTful APIs in the Laravel 7 using the passport auth. This was the basic demonstration with the example of a blog. You can expand it as per your requirements. Laravel provides the API request security to prevent any un-authenticated access. This will help you out to secure your data by inspecting it. So, that’s all for this post. Please let me know in the comment section, if you will have any problem regarding this post. I will try to resolve as soon as possible.
Leave a Reply