in this tutorial we are going to create a mini full stack application using laravel for back-end as a CRUD REST API and Angular for front-end .
required tools for this application
WampServer or XAMPP for using Apache and MySQL for our Database
Download the Composer installer for Windows
after Runing the installer, it will set up Composer globally on your system.
https://getcomposer.org/download/
composer global require laravel/installer
there is two way to install laravel project in our machine ,
Run the following command to create a new Laravel project:
laravel new my-laravel-api
final results should look like this :
or we can install laravel with Composer
composer create-project laravel/laravel my-laravel-api
if you want to install specific version there is so many Syntax , this is the most popular :
composer create-project laravel/laravel=7.4 my-laravel-api
Installation Steps
cd my-laravel-api
*Installation Sanctum : *
Laravel Sanctum is a lightweight package for Laravel that enables token-based authentication for APIs. It simplifies the process of generating, managing, and authenticating tokens, providing a secure way to protect API endpoints.
- installing sanctum
composer require laravel/sanctum
After successfully install package, we need to publish configuration file with following command :
The above command will create a create_personal_access_tokens_table.php in your /database/migrations folder and a sanctum.php file inside the /config folder, once you have verified the creation of those two files, the next thing to do is to migrate the new migration file, and you do that with the following command:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
create migration for data :
php artisan make:migration create_posts_table
replace your migration in posts with any column you want to add:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->longText('description');
$table->timestamps();
});
}
or we can create student model and migration with same command line
creating our model with migration file:
php artisan make:model Post -m
updating our model with this lines :
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'description'];
}
now we should create a database manually in mysql and add it to the . env file :
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tplaravel
DB_USERNAME=root
DB_PASSWORD=
we require to get default migration for create new sanctum tables and posts in our database. so let's run bellow command.
php artisan migrate
the result should look like this :
- Create sancthum Auth and CRUD Controller
php artisan make:controller Api\AuthController
php artisan make:controller Api\PostController --model=Post
Now update AuthContoller with
<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Sanctum\PersonalAccessToken;
class AuthController extends Controller
{
/**
* Create User
* @param Request $request
* @return User
*/
public function createUser(Request $request)
{
try {
//Validated
$validateUser = Validator::make(
$request->all(),
[
'name' => 'required',
'email' => 'required|email|unique:users,email',
'password' => 'required'
]
);
if ($validateUser->fails()) {
return response()->json([
'status' => false,
'message' => 'validation error',
'errors' => $validateUser->errors()
], 401);
}
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password)
]);
return response()->json([
'status' => true,
'message' => 'User Created Successfully',
'token' => $user->createToken("API TOKEN")->plainTextToken
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
/**
* Login The User
* @param Request $request
* @return User
*/
public function loginUser(Request $request)
{
try {
$validateUser = Validator::make(
$request->all(),
[
'email' => 'required|email',
'password' => 'required'
]
);
if ($validateUser->fails()) {
return response()->json([
'status' => false,
'message' => 'validation error',
'errors' => $validateUser->errors()
], 401);
}
if (!Auth::attempt($request->only(['email', 'password']))) {
return response()->json([
'status' => false,
'message' => 'Email & Password does not match with our record.',
], 401);
}
$user = User::where('email', $request->email)->first();
return response()->json([
'status' => true,
'message' => 'User Logged In Successfully',
'token' => $user->createToken("API TOKEN")->plainTextToken
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function logoutUser(Request $request)
{
// Get bearer token from the request
$accessToken = $request->bearerToken();
// Get access token from database
$token = PersonalAccessToken::findToken($accessToken);
// Revoke token
$token->delete();
return [
'message' => 'user logged out'
];
}
}
custumize message for not login users :
first step go to Middleware/Authenticate.php
use Illuminate\Auth\AuthenticationException;
// replace your redirect method by this one :
protected function redirectTo($request)
{
if ($request->expectsJson()) {
throw new AuthenticationException('Unauthenticated.');
}
return response()->json(['valid' => auth()->check()]);
}
To change the "Route [login] not defined" error message in Laravel Sanctum's controller, you can modify the app/Exceptions/Handler.php file. Follow these steps:
Open the app/Exceptions/Handler.php file.
Inside the render method, add the following code:
use Illuminate\Auth\AuthenticationException;
use Illuminate\Validation\ValidationException;
public function render($request, Throwable $exception)
{
if ($exception instanceof AuthenticationException) {
return response()->json(['message' => 'you are not logged'], 401);
}
return parent::render($request, $exception);
}
and update your PostController :
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::all();
return response()->json([
'status' => true,
'posts' => $posts
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
// store one post with our request post api { "title" : "test","description":"details"}
// public function store(Request $request)
// {
// $post = Post::create($request->all());
// return response()->json([
// 'status' => true,
// 'message' => "Post Created successfully!",
// 'post' => $post
// ], 200);
// }
public function store(Request $request)
{
$postsData = $request->all();
$posts = [];
foreach ($postsData as $postData) {
$post = Post::create($postData);
$posts[] = $post;
}
return response()->json([
'status' => true,
'posts' => $posts
], 201);
}
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$post = Post::find($id);
if (!$post) {
return response()->json([
'status' => false,
'message' => 'Post not found'
], 404);
}
return response()->json([
'status' => true,
'post' => $post
]);
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function edit(Post $post)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
$post->update($request->all());
return response()->json([
'status' => true,
'message' => "Post Updated successfully!",
'post' => $post
], 200);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function destroy(Post $post)
{
$post->delete();
return response()->json([
'status' => true,
'message' => "Post Deleted successfully!",
], 200);
}
}
php artisan route:clear
In routes\api.php file update the API
In Laravel, the Route::apiResource() method is used to define a set of RESTful API routes for a resource. In this case, the resource being defined is posts, and it is associated with the PostController class.
The apiResource() method automatically generates the following routes for the posts resource:
GET /posts: get lists of all posts.
POST /posts: Creates a new post.
GET /posts/{id}: Retrieves a specific post by its ID.
PUT /posts/{id}: Updates a specific post by its ID.
DELETE /posts/{id}: Deletes a specific post by its ID.
PATCH /posts/{id}:Updates a specific column in a post by its ID.
dont forget to add Bearer in your curl or header options after login or register for every action you want to call because we are using middleware for securing our Rest API
note :
By using either the $fillable or $guarded property, you have control over which attributes can be assigned via mass assignment, providing a level of security and control over your model's data.
protected $fillable = ['title', 'description'];
example of storing multi posts with our rest api :
[
{
"title": "t2",
"description": "details"
},
{
"title": "t3",
"description": "more details"
}
]
Route::post('/auth/register', [AuthController::class, 'createUser']);
Route::post('/auth/login', [AuthController::class, 'loginUser']);
Route::post('/auth/logout', [AuthController::class, 'logoutUser']);
Route::apiResource('posts', PostController::class)->middleware('auth:sanctum');
Github Code Source :
Top comments (0)