V?i s? phát tri?n m?nh m? c?a xu h??ng phát tri?n web Single page application, s? d?ng RESTful API là l?a ch?n t?t nh?t. Trong bài vi?t này, chúng ta s? cùng xây d?ng và test m?t API ??n gi?n nh?ng v?n m?nh m? b?ng cách s? d?ng Laravel Framework
Cài ??t Laravel và k?t n?i Database
ch?y l?nh kh?i t?o project laravel (máy ?ã cài composer):
composer create-project --prefer-dist laravel/laravel simpleapi
Trong th? m?c g?c c?a project v?a t?o, m? file .env
và nh?p thông tin database:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_name
DB_USERNAME=root
DB_PASSWORD=db_password
Trên terminal, cd vào th? m?c project, t?o server test v?i l?nh sau:
php artisan serve
m? trình duy?t web và ch?y th?: localhost:8000
T?o model và các table
Ch?y l?nh sau ?? t?o Model và migration:
php artisan make:model Post -m
M? file migration v?a t?o trong th? m?c database\migrations
và ch?nh s?a ph??ng th?c up()
:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
s?a file migration user có s?n khi t?o project:
database\migrations\2014_10_12_000000_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('api_token')->unique()->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};
ch?y l?nh migrate ?? t?o các table:
php artisan migrate
Thêm thu?c tính $fillable
vào model Post
v?a t?o s? t??ng t? nh? sau:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'content'];
}
T?o d? li?u th? nghi?m
ch?y l?nh sau ?? t?o seeder:
php artisan make:seeder PostTableSeeder
Faker ???c dùng trong các seeder bên d??i là th? vi?n có tác d?ng t?o d? li?u th? nghi?m.
Trong th? m?c database\seeders
Ch?nh s?a file PostTableSeeder.php
:
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Post;
class PostTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$faker = \Faker\Factory::create();
for ($i=0; $i < 100; $i++) {
Post::create([
'title' => $faker->sentence,
'content' => $faker->paragraph
]);
}
}
}
t??ng t?, t?o seeder cho table users:
php artisan make:seeder UserTableSeeder
Ch?nh s?a file UserTableSeeder.php
v?a t?o:
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
use Hash;
class UserTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
User::truncate(); // xóa d? li?u c?
$faker = \Faker\Factory::create();
// mã hóa password
$password = Hash::make('test123');
User::create([
'name' => 'Admin',
'email' => '[email protected]',
'password' => $password
]);
for ($i=0; $i < 5; $i++) {
User::create([
'name' => $faker->name,
'email' => $faker->email,
'password' => $password
]);
}
}
}
thêm các seeder vào DatabaseSeeder.php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call([
PostTableSeeder::class,
UserTableSeeder::class
]);
}
}
ch?y l?nh insert d? li?u th? nghi?m vào database:
php artisan db:seed
T?o Route, Controller, Request
T?o Request ?? validation
php artisan make:request PostRequest
N?i dung app\Http\Requests\PostRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'title' => 'required|max:150',
'content' => 'required'
];
}
}
T?o controller:
php artisan make:controller Api/PostController --model=Post
app\Http\Controllers\Api\PostController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
use App\Http\Requests\PostRequest;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return Post::all();
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(PostRequest $request)
{
$post = Post::create($request->all());
return response()->json($post, 201);
}
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show(Post $post)
{
return $post;
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(PostRequest $request, Post $post)
{
$post->update($request->all());
return response()->json($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(null, 204);
}
}
Thêm route vào routes\api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\PostController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::apiResource('posts', PostController::class);
Dùng Postman ?? ki?m tra k?t qu?:
Xác th?c ng??i dùng khi request Api
T?o controller Api/AuthController
php artisan make:controller Api/AuthController
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Auth;
use Str;
class AuthController extends Controller
{
public function login(Request $request)
{
$info = $request->only(['email','password']);
if (Auth::attempt($info)) {
$user = Auth::user();
$user->api_token = $user->id . Str::random(50);
$user->save();
return response()->json($user, 200);
}
else {
return response()->json(['data' => 'Invalid email or password.']);
}
}
public function logout(Request $request)
{
if (User::where('api_token', $request->api_token)->update(['api_token' => null])) {
return response()->json(['data' => 'Logged out.'], 200);
}
else {
return response()->json(['data' => 'logout failed.'], 200);
}
}
}
T?o middleware:
php artisan make:middleware CheckApiToken
app\Http\Middleware\CheckApiToken.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Models\User;
class CheckApiToken
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (!empty($request->api_token)) {
if (User::where('api_token', $request->api_token)->first()) {
return $next($request);
}
else {
return response()->json(['data' => 'Token is invalid.'], 200);
}
}
else {
return response()->json(['data' => 'Empty Token.'], 200);
}
}
}
Khai báo middleware
M? file app\Http\Kernel.php
tìm ??n thu?c tính $routeMiddleware và khai báo middleware v?a t?o:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'checkApiToken' => \App\Http\Middleware\CheckApiToken::class
];
S?a route, thêm middleware vào các route c?n xác th?c:
routes\api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\PostController;
use App\Http\Controllers\Api\AuthController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('login', [AuthController::class, 'login']);
Route::middleware('checkApiToken')->group(function() {
Route::apiResource('posts', PostController::class);
Route::post('logout', [AuthController::class, 'logout']);
});
M?i khi request api, c?n ph?i kèm theo api_token, ch?y th? laravel api trên Postman:
Done
?úng th? mình ?ang c?n, thank ad
Ng?n g?n súc tích d? hi?u, d? làm theo