NTM Solutions

Thứ Năm, 17 tháng 9, 2026

🚀LARAVEL 13 — BÀI 41: REST API

REST API là cầu nối để Laravel giao tiếp với Website, JavaScript, Mobile App hoặc các hệ thống khác thông qua HTTP và dữ liệu JSON.

Ở phần trước, chúng ta đã hoàn thành Logging & Debug.

Từ bài này, chúng ta bước sang:

🌐 PHẦN 9 — REST API

Gồm:

  • Bài 41 — REST API

  • Bài 42 — API Resource

  • Bài 43 — Sanctum

  • Bài 44 — API Authentication

Mục tiêu của phần này là biến Laravel từ một Website thông thường thành một Backend API có thể cung cấp dữ liệu cho nhiều loại ứng dụng khác nhau.


1. REST API là gì?

Khi xây dựng một Website Laravel truyền thống:

Browser
   ↓
Laravel
   ↓
Blade
   ↓
HTML

Laravel xử lý request rồi trả về HTML để trình duyệt hiển thị.

Ví dụ:

GET /blog

Laravel trả về:

<html>
    ...
</html>

Nhưng với API, cách hoạt động sẽ khác:

Website
Mobile App
JavaScript
React
Vue
Next.js
        ↓
      REST API
        ↓
     Laravel
        ↓
    Database

Laravel không nhất thiết trả về HTML.

Thay vào đó, Laravel trả về:

{
    "id": 1,
    "title": "Laravel 13 là gì?"
}

Đây chính là nền tảng của API.


2. API là gì?

API là viết tắt của:

Application Programming Interface

Có thể hiểu đơn giản:

API là một "cổng giao tiếp" cho phép các chương trình trao đổi dữ liệu với nhau.

Ví dụ Blog CMS của chúng ta có bài viết:

ID: 1
Title: Laravel 13 là gì?
Category: Laravel

Website có thể lấy dữ liệu bằng:

GET /api/posts

Laravel trả về:

[
    {
        "id": 1,
        "title": "Laravel 13 là gì?"
    },
    {
        "id": 2,
        "title": "Routing trong Laravel 13"
    }
]

Một ứng dụng mobile có thể gọi chính API đó.

Một ứng dụng React cũng có thể gọi.

Một ứng dụng Vue cũng có thể gọi.

Như vậy:

                 ┌── Website
                 │
                 ├── Mobile App
                 │
Laravel API ─────┼── React
                 │
                 ├── Vue
                 │
                 └── Third-party App

Backend chỉ cần cung cấp API.


3. REST là gì?

REST là viết tắt của:

Representational State Transfer

REST không phải là một thư viện.

REST là một phong cách thiết kế API dựa trên HTTP.

Ví dụ chúng ta có đối tượng:

Post

API có thể thiết kế:

GET     /api/posts
GET     /api/posts/1
POST    /api/posts
PUT     /api/posts/1
DELETE  /api/posts/1

Nhìn vào URL và HTTP method, chúng ta có thể hiểu API đang làm gì.


4. CRUD và REST API

REST API rất phù hợp với CRUD.

CRUDHTTPEndpoint
CreatePOST/api/posts
ReadGET/api/posts
Read oneGET/api/posts/1
UpdatePUT/PATCH/api/posts/1
DeleteDELETE/api/posts/1

Có thể hình dung:

              POSTS API

GET     /api/posts
        ↓
        Danh sách bài viết


GET     /api/posts/1
        ↓
        Chi tiết bài viết


POST    /api/posts
        ↓
        Tạo bài viết


PUT     /api/posts/1
        ↓
        Cập nhật bài viết


DELETE  /api/posts/1
        ↓
        Xóa bài viết

Đây là cấu trúc rất phổ biến khi thiết kế REST API.


5. HTTP Methods

REST API sử dụng các HTTP method chính.

GET

Dùng để lấy dữ liệu.

GET /api/posts

Ví dụ:

Lấy danh sách bài viết

POST

Dùng để tạo dữ liệu mới.

POST /api/posts

Ví dụ gửi:

{
    "title": "Laravel 13 REST API",
    "category_id": 1
}

PUT

Thường dùng để cập nhật toàn bộ resource.

PUT /api/posts/1

PATCH

Thường dùng để cập nhật một phần resource.

PATCH /api/posts/1

Ví dụ chỉ thay đổi:

{
    "title": "Laravel 13 API"
}

DELETE

Dùng để xóa resource.

DELETE /api/posts/1

6. API trả về JSON

Một trong những điểm quan trọng nhất khi xây dựng API là dữ liệu thường được trao đổi dưới dạng JSON.

Ví dụ:

{
    "id": 1,
    "title": "Laravel 13",
    "status": "published"
}

Laravel có thể trả về JSON rất đơn giản.

Ví dụ:

return response()->json([
    'message' => 'Hello API'
]);

Kết quả:

{
    "message": "Hello API"
}

Laravel cũng có thể tự chuyển array thành JSON response trong nhiều trường hợp.


7. Laravel 13 và API routes

Một điểm rất quan trọng đối với người học Laravel hiện nay:

Laravel không nhất thiết tạo sẵn routes/api.php trong một project mới.

API routing là phần có thể cài đặt thêm.

Trong Laravel, chúng ta có thể sử dụng:

php artisan install:api

Lệnh này dùng để cài đặt API routing và chuẩn bị cấu trúc cần thiết cho API. Laravel cũng sử dụng lệnh này trong quá trình thiết lập Sanctum ở các phiên bản hiện đại.

Sau khi chạy:

php artisan install:api

project sẽ có thêm:

routes/
├── web.php
├── console.php
└── api.php

8. web.phpapi.php

Có thể hiểu đơn giản:

routes/web.php

Dành cho Website:

Browser
   ↓
web.php
   ↓
Controller
   ↓
Blade
   ↓
HTML

routes/api.php

Dành cho API:

Client
   ↓
api.php
   ↓
Controller
   ↓
JSON

API routes hướng tới các request stateless, khác với nhóm route web vốn có session, cookie và CSRF protection.


9. Tạo API route đầu tiên

Sau khi chạy:

php artisan install:api

mở:

routes/api.php

Thêm:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/hello', function () {
    return response()->json([
        'message' => 'Hello Laravel 13 API'
    ]);
});

Chạy Laravel:

php artisan serve

Sau đó truy cập:

http://127.0.0.1:8000/api/hello

Kết quả:

{
    "message": "Hello Laravel 13 API"
}

Chúng ta vừa tạo API đầu tiên.


10. Vì sao có /api?

Khi route được khai báo trong API routing:

Route::get('/hello', ...);

URL API thường sẽ là:

/api/hello

Thay vì:

/hello

Do đó:

routes/api.php

có thể chứa:

Route::get('/posts', ...);

và client gọi:

GET /api/posts

11. API lấy danh sách Posts

Bây giờ chúng ta áp dụng vào Blog CMS.

Model:

app/Models/Post.php

Trong:

routes/api.php

có thể viết:

use App\Models\Post;
use Illuminate\Support\Facades\Route;

Route::get('/posts', function () {
    return Post::all();
});

Truy cập:

GET /api/posts

Laravel có thể chuyển Eloquent model hoặc collection thành JSON response.

Ví dụ kết quả:

[
    {
        "id": 1,
        "user_id": 1,
        "category_id": 2,
        "title": "Laravel 13 là gì?",
        "slug": "laravel-13-la-gi",
        "status": "published"
    },
    {
        "id": 2,
        "user_id": 1,
        "category_id": 3,
        "title": "Laravel Routing",
        "slug": "laravel-routing",
        "status": "published"
    }
]

12. Nhưng không nên nhét quá nhiều logic vào route

Đoạn này:

Route::get('/posts', function () {
    return Post::all();
});

chạy được.

Nhưng khi project lớn lên, chúng ta không nên đưa toàn bộ logic vào route.

Thay vào đó:

Route
   ↓
Controller
   ↓
Model
   ↓
Database

Đây cũng chính là cách chúng ta đã học ở những bài Controller và CRUD trước đó.


13. Tạo API Controller

Chạy:

php artisan make:controller Api/PostController

Laravel tạo:

app/
└── Http/
    └── Controllers/
        └── Api/
            └── PostController.php

Mở file:

app/Http/Controllers/Api/PostController.php

Viết:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        return Post::all();
    }
}

14. Kết nối Route với Controller

Mở:

routes/api.php

Viết:

<?php

use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;

Route::get('/posts', [PostController::class, 'index']);

Bây giờ:

GET /api/posts

sẽ chạy:

PostController@index

Luồng hoạt động:

GET /api/posts
       ↓
routes/api.php
       ↓
PostController@index
       ↓
Post::all()
       ↓
Database
       ↓
JSON

15. API lấy một Post

Thêm vào Controller:

public function show(Post $post)
{
    return $post;
}

Route:

Route::get('/posts/{post}', [PostController::class, 'show']);

Bây giờ:

GET /api/posts/1

Laravel sẽ tìm:

Post ID = 1

và trả về JSON.

Ví dụ:

{
    "id": 1,
    "title": "Laravel 13 là gì?",
    "slug": "laravel-13-la-gi",
    "status": "published"
}

Đây chính là Route Model Binding mà chúng ta đã học ở phần Routing.


16. API chỉ lấy bài Published

Trong Blog CMS, chúng ta không muốn API công khai trả về tất cả bài viết.

Ví dụ:

draft
hidden
scheduled

không nên xuất hiện trong API public.

Model Post của chúng ta đã có scope:

Post::published()

Do đó Controller có thể viết:

public function index()
{
    return Post::published()
        ->with(['user', 'category'])
        ->latest('published_at')
        ->paginate(10);
}

Khi đó:

GET /api/posts

chỉ lấy những bài đã publish.

Đây chính là cách kết hợp:

Eloquent
+
Scope
+
Relationship
+
Pagination
+
REST API

17. API response có cấu trúc rõ ràng

Thay vì trả thẳng:

return Post::all();

chúng ta có thể tạo response:

return response()->json([
    'success' => true,
    'data' => Post::all()
]);

Kết quả:

{
    "success": true,
    "data": [
        {
            "id": 1,
            "title": "Laravel 13 là gì?"
        },
        {
            "id": 2,
            "title": "Laravel Routing"
        }
    ]
}

Cách này giúp client dễ xử lý response.


18. HTTP Status Code

API không chỉ trả dữ liệu.

API còn cần trả về HTTP status code phù hợp.

Một số status code quan trọng:

CodeÝ nghĩa
200OK
201Created
204No Content
400Bad Request
401Unauthorized
403Forbidden
404Not Found
422Validation Error
500Server Error

Ví dụ lấy dữ liệu thành công:

return response()->json([
    'data' => $posts
], 200);

19. API tạo Post

Ví dụ:

public function store(Request $request)
{
    $post = Post::create([
        'user_id' => $request->user()->id,
        'title' => $request->title,
        'slug' => $request->slug,
        'content' => $request->content,
    ]);

    return response()->json([
        'message' => 'Post created successfully',
        'data' => $post
    ], 201);
}

Nhớ import:

use Illuminate\Http\Request;

Client gửi:

POST /api/posts

Body:

{
    "title": "Laravel 13 REST API",
    "slug": "laravel-13-rest-api",
    "content": "..."
}

Nếu tạo thành công:

HTTP 201 Created

20. Validation cho API

API vẫn cần Validation giống Website.

Ví dụ:

$request->validate([
    'title' => ['required', 'string', 'max:255'],
    'slug' => ['required', 'string', 'max:255'],
    'content' => ['required', 'string'],
]);

Nếu dữ liệu không hợp lệ, Laravel có thể trả về lỗi validation dưới dạng JSON đối với request API.

Ví dụ client có thể nhận:

{
    "message": "The title field is required.",
    "errors": {
        "title": [
            "The title field is required."
        ]
    }
}

API client có thể dùng thông tin này để hiển thị lỗi cho người dùng.


21. API Update

Ví dụ:

public function update(Request $request, Post $post)
{
    $request->validate([
        'title' => ['required', 'string', 'max:255'],
        'content' => ['required', 'string'],
    ]);

    $post->update([
        'title' => $request->title,
        'content' => $request->content,
    ]);

    return response()->json([
        'message' => 'Post updated successfully',
        'data' => $post
    ]);
}

Route:

Route::put('/posts/{post}', [PostController::class, 'update']);

Client:

PUT /api/posts/1

22. API Delete

Controller:

public function destroy(Post $post)
{
    $post->delete();

    return response()->json([
        'message' => 'Post deleted successfully'
    ]);
}

Route:

Route::delete('/posts/{post}', [PostController::class, 'destroy']);

Client:

DELETE /api/posts/1

Có thể trả về:

{
    "message": "Post deleted successfully"
}

23. Resource Controller cho API

Thay vì khai báo từng route:

Route::get('/posts', ...);
Route::get('/posts/{post}', ...);
Route::post('/posts', ...);
Route::put('/posts/{post}', ...);
Route::delete('/posts/{post}', ...);

Laravel hỗ trợ resource routing.

Ví dụ:

Route::apiResource('posts', PostController::class);

Lúc này Laravel tạo nhóm route CRUD cho API.

Có thể kiểm tra bằng:

php artisan route:list

Hoặc:

php artisan route:list --path=api

Bạn sẽ thấy các route tương ứng với:

GET       /api/posts
POST      /api/posts
GET       /api/posts/{post}
PUT/PATCH /api/posts/{post}
DELETE    /api/posts/{post}

Đây là cách rất phù hợp cho Blog CMS.


24. Hoàn chỉnh PostController cơ bản

Sau khi học xong phần này, chúng ta có thể hình dung Controller:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::published()
            ->with(['user', 'category'])
            ->latest('published_at')
            ->paginate(10);

        return response()->json([
            'success' => true,
            'data' => $posts
        ]);
    }

    public function show(Post $post)
    {
        return response()->json([
            'success' => true,
            'data' => $post
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'slug' => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
        ]);

        $post = Post::create([
            ...$validated,
            'user_id' => $request->user()->id,
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Post created successfully',
            'data' => $post
        ], 201);
    }

    public function update(Request $request, Post $post)
    {
        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'slug' => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
        ]);

        $post->update($validated);

        return response()->json([
            'success' => true,
            'message' => 'Post updated successfully',
            'data' => $post
        ]);
    }

    public function destroy(Post $post)
    {
        $post->delete();

        return response()->json([
            'success' => true,
            'message' => 'Post deleted successfully'
        ]);
    }
}

Đây là API Controller cơ bản.

Tuy nhiên, trong dự án thực tế chúng ta sẽ chưa dừng ở đây.


25. Route API hoàn chỉnh

routes/api.php:

<?php

use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;

Route::apiResource('posts', PostController::class);

Kết quả:

GET       /api/posts
POST      /api/posts
GET       /api/posts/{post}
PUT       /api/posts/{post}
PATCH     /api/posts/{post}
DELETE    /api/posts/{post}

Đây chính là REST API cho resource:

posts

26. Test API bằng trình duyệt

Các request GET đơn giản có thể test trực tiếp bằng trình duyệt.

Ví dụ:

http://127.0.0.1:8000/api/posts

Hoặc:

http://127.0.0.1:8000/api/posts/1

Browser sẽ hiển thị JSON.

Ví dụ:

{
    "success": true,
    "data": {
        "id": 1,
        "title": "Laravel 13"
    }
}

27. Test API bằng Postman

Khi API có:

GET
POST
PUT
PATCH
DELETE

thì Postman sẽ thuận tiện hơn trình duyệt.

Ví dụ:

GET
http://127.0.0.1:8000/api/posts

POST:

POST
http://127.0.0.1:8000/api/posts

Body:

{
    "title": "Bài viết mới",
    "slug": "bai-viet-moi",
    "content": "Nội dung bài viết"
}

PUT:

PUT
http://127.0.0.1:8000/api/posts/1

DELETE:

DELETE
http://127.0.0.1:8000/api/posts/1

Như vậy Postman có thể đóng vai trò như một client của Laravel API.


28. API không phải là Website

Đây là điểm người mới học Laravel rất dễ nhầm.

Website:

GET /blog
        ↓
Controller
        ↓
Blade
        ↓
HTML

API:

GET /api/posts
        ↓
Controller
        ↓
Eloquent
        ↓
JSON

Hai thứ đều sử dụng Laravel.

Nhưng mục đích khác nhau.


29. Một API có thể phục vụ nhiều ứng dụng

Ví dụ chúng ta có:

                 Laravel 13 API
                       │
          ┌────────────┼────────────┐
          ↓            ↓            ↓
       Website      Android        iOS
          │            │            │
          └────────────┼────────────┘
                       ↓
                    Database

API trở thành tầng trung gian giữa frontend và database.

Ví dụ:

GET /api/posts

Website lấy dữ liệu.

Mobile App cũng gọi:

GET /api/posts

Một ứng dụng React cũng có thể gọi:

GET /api/posts

Không cần xây dựng ba hệ thống backend riêng biệt.


30. REST API trong Blog CMS của chúng ta

Project hiện tại có:

users
categories
posts

Sau khi hoàn thành phần API, chúng ta có thể xây dựng:

/api/posts
/api/categories
/api/users

Ví dụ:

GET /api/posts
GET /api/posts/1

GET /api/categories
GET /api/categories/1

Sau này có thể phát triển tiếp:

POST   /api/posts
PUT    /api/posts/1
DELETE /api/posts/1

Nhưng vấn đề tiếp theo xuất hiện:

Dữ liệu trả về có nên được đưa thẳng từ Model ra JSON hay không?

Ví dụ Model Post có:

user_id
category_id
view_count
created_at
updated_at

Trong khi frontend có thể chỉ cần:

id
title
slug
excerpt
image
published_at
category
author

Đây chính là lý do chúng ta cần học API Resource.


31. API Resource giải quyết vấn đề gì?

Hiện tại:

return $post;

Laravel có thể chuyển Model thành JSON.

Nhưng chúng ta không kiểm soát tốt cấu trúc dữ liệu.

API Resource cho phép định nghĩa:

Model
  ↓
Resource
  ↓
JSON

Ví dụ:

Post
 ↓
PostResource
 ↓
{
    id,
    title,
    slug,
    excerpt,
    image,
    category,
    author
}

Đây sẽ là nội dung của:

👉 Bài 42 — API Resource


32. API và bảo mật

Một API public không có nghĩa là:

Ai cũng được phép làm mọi thứ.

Ví dụ:

GET /api/posts

có thể public.

Nhưng:

POST /api/posts
PUT /api/posts/1
DELETE /api/posts/1

thì cần kiểm tra người dùng.

Có thể cần:

Authentication
Authorization
Token
Permission
Policy

Đây chính là phần chúng ta sẽ học tiếp trong:

Bài 43 — Sanctum
Bài 44 — API Authentication

Vì vậy trong bài này chúng ta mới chỉ xây dựng REST API cơ bản.


33. Kiến trúc REST API của Blog CMS

Sau khi hoàn thành Phần 9, kiến trúc sẽ có dạng:

                    Laravel 13
                        │
             ┌──────────┴──────────┐
             │                     │
          Website                  API
             │                     │
          web.php               api.php
             │                     │
          Controller            Controller
             │                     │
          Blade                Resource
             │                     │
           HTML                  JSON
             │                     │
             └──────────┬──────────┘
                        ↓
                     Eloquent
                        ↓
                     MySQL

Đây là một bước rất quan trọng trong quá trình chuyển từ:

Laravel Website

sang:

Laravel Backend API


34. Bài tập thực hành

Bài tập 1

Cài API routing:

php artisan install:api

Kiểm tra:

routes/api.php

Bài tập 2

Tạo:

/api/hello

Trả về:

{
    "message": "Hello Laravel 13 API"
}

Bài tập 3

Tạo:

GET /api/posts

Trả về danh sách Post.


Bài tập 4

Tạo:

GET /api/posts/{post}

Trả về một Post.


Bài tập 5

Tạo REST CRUD:

GET       /api/posts
GET       /api/posts/{post}
POST      /api/posts
PUT       /api/posts/{post}
DELETE    /api/posts/{post}

Có thể sử dụng:

Route::apiResource('posts', PostController::class);

Bài tập 6

Dùng Postman kiểm tra:

GET
POST
PUT
DELETE

và quan sát:

HTTP Status Code
JSON Response
Validation Error

35. Tổng kết

Trong bài này, chúng ta đã làm quen với:

  • REST API

  • API là gì?

  • REST là gì?

  • HTTP Methods

  • GET

  • POST

  • PUT

  • PATCH

  • DELETE

  • JSON

  • API routes

  • php artisan install:api

  • routes/api.php

  • API Controller

  • Route Model Binding

  • response()->json()

  • HTTP Status Code

  • Validation

  • Route::apiResource()

  • Test API bằng Browser

  • Test API bằng Postman

  • REST API trong Blog CMS

Quan trọng nhất cần nhớ:

Website
   ↓
HTML

API
   ↓
JSON

Và:

GET     → Read
POST    → Create
PUT     → Update
PATCH   → Update một phần
DELETE  → Delete

Một REST API cơ bản của Blog CMS:

/api/posts
/api/posts/{post}

có thể trở thành backend dùng chung cho:

Website
Mobile App
React
Vue
Next.js
Third-party Application

🎯 Lộ trình tiếp theo

Chúng ta đã có REST API.

Nhưng response hiện tại vẫn còn khá "thô":

return $post;

hoặc:

return Post::all();

Ở bài tiếp theo, chúng ta sẽ học cách kiểm soát chính xác dữ liệu JSON trả về bằng:

🚀 BÀI 42 — API RESOURCE

Luồng xử lý sẽ trở thành:

Database
    ↓
Eloquent Model
    ↓
API Resource
    ↓
JSON
    ↓
Frontend / Mobile App

Đây là bước rất quan trọng để biến API Laravel thành một API có cấu trúc rõ ràng và phù hợp với dự án thực tế.

Không có nhận xét nào:

Đăng nhận xét

Facebook Youtube RSS