Restful API trong Laravel

Restful API trong Laravel hướng dẫn bạn cách triển khai API trong Laravel để tạo nên khả năng trao đổi và quản lý các resource từ xa.


Khi lập trình với Laravel , bạn cũng cần phải biết về cách triển khai API. Restful API là một chuẩn phổ biến ngày nay dùng để thiết kế giao tiếp cho ứng dụng web nhằm trao đổi và quản lý các resource từ xa.

RESTful hoạt động dựa trên http với hoạt động request từ xa đến server để thực hiện lấy, thêm,xóa , sửa dữ liệu. Với Restful, dạng dữ liệu trao đổi giữa client/server là JSON hoặc XML, nhưng JSON thường được dùng hơn.

Giới thiệu Restful API

Để triển khai Restful API trong Laravel, bạn cần dùng một tool để test, đó là Postman. Hãy vào địa chỉ sau để download và cài vào máy https://postman.com/downloads/ . Việc cài đặt tool này là đơn giản và không có gì đặc biệt, Bạn tự thực hiện nhé.

Các method trong http

Giao thức http hỗ trợ tạo request đến server với nhiều method khác nhau: GET, POST, PUT, PATCH, DELETE… Restful dùng các method này để diễn tả các hành động xem, thêm, sửa, xóa dữ liệu (tài nguyên) trên server. Cụ thể như saiL

  • Method GET: được dùng để diễn tả hành động muốn xem chi tiết 1 tài nguyên hoặc lấy danh sách tài nguyên trên server.
  • Method POST: được dùng để diễn tả hành động muốn thêm 1 tài nguyên mới trên server.
  • Method PUT: được dùng để diễn tả hành động muốn cập nhật 1 tài nguyên đang có trên server.
  • Method DELETE: được dùng để diễn tả hành động muốn xóa 1 tài nguyên đang có trên server.
Các method trong http

URI Trong Restful API

Restful API quản lý tài nguyên thông qua các URI (địa chỉ web).  Bạn xem ví dụ sau để rõ hơn:

  • Lấy resource từ server, URI sử dụng như sau:
    GET http://abc.com/api/products  => trả về danh sách các product
    GET http://abc.com/api/products/1  => trả về product có id là 1
  • Khi cần tạo mới một resource trên server, sử dụng URI như sau:
    POST http://abc.com/api/products  
  • Cập nhật 1 resource trên server , địa chỉ được dùng theo dạng:
    PUT http://abc.com/api/products/1
  • Xoá 1 resource trên server, URI là
    DELETE http://abc.com/api/products/1   

Ở trên, products là tài nguyên cần quản lý còn 1 là id của tài nguyên.

Giới thiệu về JSON

JSON là định dạng dữ liệu chính được dùng chủ yếu trong Restful API. Cú pháp của JSON rất ngắn gọn, định dạng này giúp diễn tả rất dễ dàng dữ liệu có cấu trúc.

Một đối tượng dữ liệu json được đặt trong dấu {  }, trong đó dữ liệu được diễn tả thành từng cặp key:value cách nhau bởi dấu phẩy. Còn mảng dữ liệu json được diễn tả bằng dấu [  ]. Mời xem ví dụ json mô tả 1 sản phẩm:

Còn code như sau là ví dụ json mô tả 1 mảng sản phẩm

Các status code http cần biết

Khi request đến một API server, Bạn sẽ nhận được status code trả về, giá trị của status cho biết kết quả của request. Sau đây là một số giá trị status thường gặp:

  • 200 OK – thành công, dùng cho các phương thức GET, PUT, PATCH, DELETE.
  • 201 Created – Trả về khi resouce được tạo thành công.
  • 204 No Content – Trả về khi resource xoá thành công.
  • 304 Not Modified – Client có thể sử dụng dữ liệu cache.
  • 400 Bad Request – Request không hợp lệ
  • 401 Unauthorized – Request cần phải có auth.
  • 403 Forbidden – bị từ chối không cho phép.
  • 404 Not Found – Không tìm thấy resource từ URI
  • 405 Method Not Allowed – Phương thức bị cấm với user hiện tại.
  • 429 Too Many Requests – Request bị từ chối do bị giới hạn

Những việc cần làm khi tạo Restful API trong Laravel

Sau đây là những việc bạn cần thực hiện khi muốn triển khai Restful API trong Laravel cho mục đích quản trị dữ liệu từ xa:

  1. Cài api cho ứng dụng laravel
  2. Tạo table để chứa dữ liệu nếu chưa tạo (ví dụ san_pham)
  3. Tạo và cấu hình model để tương tác với table
  4. Tạo resource để transform data
  5. Tạo controller và các action, mỗi action trả về dữ liệu json
  6. Tạo các route api dẫn vào các action trong controller
  7. Viết code cho các action trong controller

Cài api cho ứng dụng laravel

Trong project laravel, chạy lệnh sau để cài đặt api

php artisan install:api

Tạo table trong database để chứa dữ liệu

Bạn có thể tạo bằng tay nhưng nên dùng công cụ migration trong laravel cho nhanh và tiện cho team.

public function up(): void {
Schema::create('san_pham', function (Blueprint $table) {
$table->id();
$table->string('ten_sp');
$table->integer('gia');
$table->integer('id_loai');
$table->timestamps();
});
}
public function down(): void {
Schema::dropIfExists('san_pham');
}

Tạo và cấu hình model

Sau khi tạo table, bạn cần tạo model để tương tác với table:

php artisan make:model san_pham

và cấu hình cho model mới tạo:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class san_pham extends Model {
    use HasFactory;
    protected $table = 'san_pham';
    public $primaryKey = 'id';
    protected $fillable = ['ten_sp', 'gia', 'id_loai'];
}

Sau khi cấu hình model, chèn vài dòng dữ liệu vào table (dùng seeder)

<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\san_pham;
class DatabaseSeeder extends Seeder {
public function run(): void {
$sp_arr = [
[ "ten_sp"=>"Asus TUF Gaming 75",
"gia"=>18490000,"id_loai"=>"1"],
[ "ten_sp"=>"Acer Gaming Aspire",
"gia"=>16990000,"id_loai"=>"2"],
[ "ten_sp"=>"MSI Gaming GF63 15",
"gia"=>16990000,"id_loai"=>"4"],
[ "ten_sp"=>"Lenovo Ideapad 55H",
"gia"=>15990000,"id_loai"=>"3"],
[ "ten_sp"=>"Acer Gaming Nit i7",
"gia"=>21990000,"id_loai"=>"2"],
[ "ten_sp"=>"Asus Gaming R5 755",
"gia"=>19290000,"id_loai"=>"1"],
[ "ten_sp"=>"Asus Air 13 M3",
"gia"=>38490000, "id_loai"=>"1"],
[ "ten_sp"=>"Asus fq5229TU i3",
"gia"=>10790000, "id_loai"=>"1"],
[ "ten_sp"=>"Acer Aspire 51M",
"gia"=>11490000,"id_loai"=>"2"],
[ "ten_sp"=>"MSI Gaming Thin 1H",
"gia"=>16990000,"id_loai"=>"4"],
[ "ten_sp"=>"MSI GF63 12UCX i5",
"gia"=>17290000,"id_loai"=>"4"],
[ "ten_sp"=>"MSI Sword HX B14G",
"gia"=>37990000,"id_loai"=>"4"],
[ "ten_sp"=>"MSI HX B14VFKG i7",
"gia"=>36590000,"id_loai"=>"4"],
[ "ten_sp"=>"Lenovo LOQ i5 12X",
"gia"=>21490000,"id_loai"=>"3"],
[ "ten_sp"=>"Lenovo Gaming i5",
"gia"=>20790000,"id_loai"=>"3"],
];
for($i=0; $i<count($sp_arr); $i++) san_pham::create($sp_arr[$i]);
}//run
}

Tạo resource để transform data

Resource giúp chuyển (transform) dữ liệu cho thân thiện với người dùng. Ví dụ như định dạng thời gian, đổi tên các field cho đẹp…. trước khi response. Để tạo 1 class resource (san_pham), chạy lệnh sau:

php artisan make:resource san_pham

Khi chạy xong lệnh, file resource được tạo ra và lưu trong folder app/Http/Resources, trong đó có hàm toArray() – là nơi khai báo các định dạng mong muốn.

<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class san_pham extends JsonResource {
    public function toArray(Request $request): array  {
        return [
        'id' => $this->id,
        'ten_sp' => $this->ten_sp,
        'gia_sp' => $this->gia,   
        'id_loai' => $this->id_loai,   
        'cap_nhat' => $this->updated_at->format('d/m/Y')
        ];
    }    
}

Tạo controller và các action trả về dữ liệu json

Tạo controller rồi định nghĩa các action. Ở đầu crong controller, use Model để tương tác database và resource để format dữ liệu. Mỗi action trả về dữ liệu json với lệnh response()->json()

php artisan make:controller SanPhamController 

Code trong controller

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\san_pham;
use App\Http\Resources\san_pham as SanPhamResource;
class SanPhamController extends Controller {
  function index(){
      $listsp = san_pham::all();  
      $data = SanPhamResource::collection($listsp);      
      return response()->json($data);
  }
  function chi_tiet($id = 0){
      $sp = san_pham::findOrFail($id);  
      $data = new SanPhamResource($sp);      
      return response()->json($data);
  }
  function sp_trong_loai($id=0){
    $listsp =san_pham::where('id_loai', $id)
    ->orderBy('id','desc')->get();
    $data = SanPhamResource::collection($listsp);
    return response()->json($data);
  }
}

Tạo các route api dẫn vào các action trong controller

Tạo route để dẫn vào các action trong controller. Các route này định nghĩa trong file routes/api.php. Khi thực hiện request đến các route này, phải có thêm prefix là api

use App\Http\Controllers\SanPhamController;
Route::get('sp', [SanPhamController::class, 'index']);
Route::get('sp/{id}', [SanPhamController::class, 'chi_tiet']);
Route::get('loai/{id}', [SanPhamController::class, 'sp_trong_loai']);

Tạo route apiResource cho controller api

Nếu bạn có tạo 1 controller để có sẵn các hàm thêm sửa xóa dữ liệu như sau:

php artisan make:controller AdminSPController --api

Thì bạn có thể route vào tất cả các action của controller api bằng lệnh sau trong routes/api.php

use App\Http\Controllers\AdminSPController;
Route::apiResource('admin/sp', AdminSPController::class);

Viết code cho các action trong controller

Trong mỗi action của controller, bạn code xử lý nghiệp vụ bình thường theo yêu cầu, nhưng ở cuối mỗi action không nạp view mà thay vào đó là response dữ liệu json về cho client thông qua hàm response()->json()

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\san_pham;
use App\Http\Resources\san_pham as SanPhamResource;
class SanPhamController extends Controller {
function index(){
$listsp = san_pham::all();
$data = SanPhamResource::collection($listsp);
return response()->json($data);
}
function chi_tiet($id = 0){
$sp = san_pham::findOrFail($id);
$data = new SanPhamResource($sp);
return response()->json($data);
}
function sp_trong_loai($id=0){
$listsp =san_pham::where('id_loai', $id)
->orderBy('id','desc')->get();
$data = SanPhamResource::collection($listsp);
return response()->json($data);
}
}

Authentication sử dụng Sanctum

Sau đây là các bước cơ bản hướng dẫn để triển khai authentication khi dùng API:

1.Cấu hình model user để dùng token

<?php //app/Models/User.php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable {
use HasFactory, Notifiable, HasApiTokens;
protected $fillable = ['name', 'email', 'password', ];
protected $hidden = ['password', 'remember_token',];
protected function casts(): array {
return ['email_verified_at'=>'datetime','password'=>'hashed',];
}
}

2. Cấu hình sanctum cho api token

– Mở file config/sanctum.php khai báo cho phép domain  request api đến trong biến stateful

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:8000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),

 3. Chạy lệnh php artisan config:publish cors sẽ thấy trong folder config có thểm file cors.php . Xong mở file cors.php để khai báo

'supports_credentials' => true,

Ngoài ra cần mở file bootstrap/app.php caấu hình

->withMiddleware(function (Middleware $middleware) {
$middleware->statefulApi();
})

4.Tạo 1 controller, ví dụ AuthController.php và viết các hàm thực hiện login, logout, register…

public function login(Request $request) {
  if (!Auth::attempt($request->only('email', 'password'))){
     return response()->json(['message' => 'Unauthorized'], 401);
  }
  $user= User::where('email', $request['email'])->firstOrFail();
  $token= $user->createToken('auth_token')->plainTextToken;
  return response()->json([
    'message'=>'Chào '.$user->name.'! Chúc an lành’,
    'access_token' => $token, 'token_type' => 'Bearer',
  ]);
}

public function logout()  {
   auth()->user()->tokens()->delete();
   return ['message' => 'Bạn đã thoát và token đã xóa'];
}

6. Trong routes/api.php, định nghĩa các route và bảo vệchúng bởi auth:sanctum

use App\Http\Controllers\AuthController;
//API route để đăng nhập
Route::post('/login_api', [AuthController::class, 'login']);
Route::post(‘/login_api', [AuthController::class, 'login_']);

Route::group(['middleware' => ['auth:sanctum']] , function () {
    Route::get('/profile', function(Request $request) { 
        return auth()->user();
    });
    Route::post('/logout', [AuthController::class, 'logout']);
});

Test kết quả với postman

Đăng nhập

Xem thêm tài liệu ở đây nhé https://laravel.com/docs/9.x/eloquent-resources