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 Restful API. Vậy nó là gì? 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. Tạo table để chứa dữ liệu nếu chưa tạo (Product)
  2. Tạo model (Product) và khai báo các field trong model
  3. Tạo Eloquent resource để transform data
  4. Tạo Controller resource chứa các action xem, them sửa, xóa resource
  5. Tạo các route api dẫn vào các action trong controller
  6. Viết code cho chức năng thêm resource và test
  7. Viết code cho chức năng sửa resource và test
  8. Viết code cho hiện danh sách resource và test
  9. Viết code xóa 1 resource và test
  10. Viết code hiện chi tiết 1 resource và test1

1. Tạo table trong database để chứa dữ liệu (product)

  • Chạy lệnh sau để tạo migration: 
    php artisan make:migration create_products_table
  • Khai báo các field trong file migration mới tạo
public function up() {
   Schema::create('products', function (Blueprint $table) {
     $table->id();
     $table->string('name');
     $table->integer('price');
     $table->timestamps();
   });
}
  • Chạy migration để tạo table:  php artisan migrate

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

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

  • Chạy lệnh sau để tạo model:
    php artisan make:model Product
  • Khai báo các field trong file model mới tạo:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
   use HasFactory;
   protected $fillable = ['name', 'price'];
}
  • Chèn vài dòng dữ liệu vào table (dùng seeder): Bạn tự thực hiện nhé

3. Tạo Eloquent Resource

Eloquent 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 eloquent resource (product), chạy lệnh sau: php artisan make:resource Product

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.

Ví dụ: định nghĩa tên thân thiện cho field và định dạng lại dữ liệu các field

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Product extends JsonResource {
   public function toArray($request) {
     return [
       'id' => $this->id,
       'tensp' => $this->name,
       'gia' => $this->price,
       'created_at' => $this->created_at->format('d/m/Y'),
       'updated_at' => $this->updated_at->format('d/m/Y'),
     ];
   }
}

4.Tạo resource controller

  • Tạo controller resource để có sẵn các hàm tương tác db, chạy lệnh như sau:
    php artisan make:controller ProductController –resource
  • Mở file controller resource, sẽ thấy các hàm có sẵn.
  • Thêm các lệnh nhúng validator để kiểm tra dữ liệu, nhúng model và eloquent resource để dùng.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator;
use App\Models\Product;
use App\Http\Resources\Product as ProductResource;
class ProductController extends Controller {
  public function index(){}
  public function create() {}
  public function store(Request $request) { }
  public function show($id) { }
  public function edit($id) { }
  public function update(Request $request,$id){}
  public function destroy($id) { }
}
  • index(): nơi code để trả về list các tài nguyên
  • store(): lnơi code để tạo (lưu) tài nguyên mới
  • update(): nơi code để cập nhật 1 tài nguyên.
  • destroy(): nơi code để xóa 1 tài nguyên
  • create() , edit() có thể xóa

5. Tạo route api trong laravel

Tạo route là việc quan trọng khi tạo Restful API trong Laravel. Mục đích của tạo route là để có các path đưa user đến các action trong controller đã tạo ở trên. Để tạo các route api, bạn mở file routes/api.php lên để định nghĩa nhé.

Khi user thực hiện request đến các route này, phải có thêm prefix là api, (có thể đổi trong app\Providers\RouteServiceProvider.php)

Định nghĩa route trong api.php có 2 cách:

Cách 1: Khai báo route với 1 method cụ thể (get, post), route (sp), action (index, store). Ví dụ:

use App\Http\Controllers\ProductController;
Route::get('sp', [ProductController::class, 'index']);
Route::post('sp', [ProductController::class, 'store']);

Cách 2: Khai báo route với lệnh Route::resource để dùng chung route cho các method get, post, put, delete dẫn vào các action của controller
Route::resource(‘products’, ProductController::class);

Lệnh trên tạo ra cácroute dẫn vào các action như sau:

6. Code tạo resource mới

Trong controller, hàm store() là nơi code tạo resource mới, sau đó trả về:

  • status (true/false) cho biết hoạt động thành công/thất bại.
  • message: text mô tả kết quả hoạt động
  • data :  tài nguyên mới tạo
use App\Models\Product;
use App\Http\Resources\Product as ProductResource;
use Illuminate\Support\Facades\Validator;
//...

public function store(Request $request) {
 $input = $request->all(); 
 $validator = Validator::make($input, [
   'name' => 'required', 'price' => 'required'
 ]);
 if($validator->fails()){
    $arr = [
      'success' => false,
      'message' => 'Lỗi kiểm tra dữ liệu',
      'data' => $validator->errors()
    ];
    return response()->json($arr, 200);
 }
 $product = Product::create($input);
 $arr = ['status' => true,
    'message'=>"Sản phẩm đã lưu thành công",
    'data'=> new ProductResource($product)
 ];
 return response()->json($arr, 201);
}

7. Code cập nhật một resource

Trong controller, hàm update() , Bạn code để cập nhật tài nguyên, sau đó trả về các dữ liệu sau:

  • status (true/false) cho biết hoạt động thành công/thất bại.
  • message: text mô tả kết quả hoạt động
  • data : tài nguyên mới cập nhật
public function update(Request $request, Product $product){
  $input = $request->all();
  $validator = Validator::make($input, [
     'name' => 'required', 'price' => 'required'
  ]);
  if($validator->fails()){
     $arr = [
       'success' => false,
       'message' => 'Lỗi kiểm tra dữ liệu',
       'data' => $validator->errors()
     ];
     return response()->json($arr, 200);
  }
  $product->name = $input['name'];
  $product->price = $input['price'];
  $product->save();
  $arr = [
     'status' => true,
     'message' => 'Sản phẩm cập nhật thành công',
     'data' => new ProductResource($product)
  ];
  return response()->json($arr, 200);
}

8. Code trả về danh sách resource

Trong controller, hàm index() là nơi code để trả về danh sách resource. Sau đó trả về ba loại dữ liệu sau:

  • status (true/false) cho biết hoạt động thành công/ thất bại.
  • message: text mô tả kết quả hoạt động
  • data : là mảng json các tài nguyên
public function index() {
  $products = Product::all();
  $arr = [
  'status' => true,
  'message' => "Danh sách sản phẩm",
  'data'=>ProductResource::collection($products)
  ];
   return response()->json($arr, 200);
}

9. Code xóa một resource

Trong controller, hàm destroy() là nơi code để xóa 1 tài nguyên, sau đó trả về:

  • status (true/false) cho biết thành công/thất bại.
  • message: text mô tả kết quả hoạt động
  • data : không có
public function destroy(Product $product){
   $product->delete();
   $arr = [
      'status' => true,
      'message' =>'Sản phẩm đã được xóa',
      'data' => [],
   ];
   return response()->json($arr, 200);
}

10. Code thông tin chi tiết một resource

Trong controller, hàm show() là nơi code để lấy 1 tài nguyên, sau đó trả về:

  • status (true/false) cho biết thành công/thất bại.
  • message: text mô tả kết quả hoạt động
  • data : chi tiết tài nguyên
public function show($id) {
 $product = Product::find($id);
 if (is_null($product)) {
    $arr = [
      'success' => false,
      'message' => 'Không có sản phẩm này',
      'dara' => []
    ];
    return response()->json($arr, 200);
 }
 $arr = [
   'status' => true,
   'message' => "Chi tiết sản phẩm ",
   'data'=> new ProductResource($product)
 ];
 return response()->json($arr, 201);
}

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ài gói sanctum:    composer require laravel/sanctum
2.Publish cấu hình mà migration của sanctum:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider“

3.Chạy migration để tạo các table cần dùng: php artisan migrate
4.Tạo AuthController:    php artisan make:controller API/AuthController
5.Mở Controllers/API/AuthController.php mới tạo viết các hàm thực hiện login, logout, register…

<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Auth;
use Validator;
use App\Models\User;
class AuthController extends Controller {
  public function register(Request $request) {
    $validator = Validator::make($request->all(),[
       'name' => 'required|string|max:255’,
       'email' => 'required|string|email|max:255|unique:users’,
       'password' => 'required|string|min:8’
    ]);
    if($validator->fails())return response()->json($validator->errors());
    $user = User::create([
       'name' => $request->name,
       'email' => $request->email,
       'password' => Hash::make($request->password)
    ]);
    $token = $user->createToken('auth_token')->plainTextToken;
    return response()->json(
    ['data' => $user,'access_token' => $token, 'token_type' => 'Bearer', ]);
  }
  ///login
  //logout
}//class
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 ứng dụng và token đã xóa'];
}

6.Định nghĩa các route cần được bảo vệ trong routes/api.php

use App\Http\Controllers\API\AuthController;
//API route để đăng ký
Route::post('/login', [AuthController::class, 'register']);
//API route để đăng nhập
Route::post(‘/login', [AuthController::class, 'login']);
Route::group(['middleware' => ['auth:sanctum']], function () {
    Route::get('/profile', function(Request $request) { 
        return auth()->user();
    });
    // API route thoát
    Route::post('/logout', [AuthController::class, 'logout']);
});

7.Bảo vệ các route

use App\Http\Controllers\API\AuthController;
//API route để đăng ký
Route::post('/dangky', [AuthController::class, 'register']);
//API route để đăng nhập
Route::post('/dangnhap', [AuthController::class, 'login']);
Route::group(['middleware' => ['auth:sanctum']], function () {
    Route::get('/profile', function(Request $request) { 
        return auth()->user();
    });
    // API route thoát
    Route::post('/logout', [AuthController::class, 'logout']);
});

Test kết quả với postman

Dùng Postman request uri đăng ký

Thông tin User sẽ được chèn vào database, có cả token

Đăng nhập

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