Làm như thế nào để tạo một RESTful API bằng laravel

Ngày nay, WEB API là một yêu cầu hết sức cơ bản trong bất kỳ một trang web phổ biến nào. Vì vậy hôm nay mình sẽ cùng tìm hiểu để xây dựng một API đúng chuẩn RESTful trong PHP thông qua framework Laravel.

Vì sao lại chọn framework Laravel

Laravel hiện nay là một framework PHP được ưa thích nhất hiện nay và được hỗ trợ rất mạnh mẽ từ nhà phát triển. Laravel được xây dựng trên một cơ sở vững chắc là Symfony nhưng lại được tích hợp thêm rất nhiều thành phần mạnh mẽ như "templating engine, ORM, command line Artisan".

Cài đặt

Cài đặt Laravel bạn có thể sử dụng Composer, một trình quản lý các thư viện được ưa chuộng với dev PHP. Mọi tài liệu hướng dẫn cài đặt Laravel tại: Hướng dẫn.

Bắt đầu

Để bắt đầu, chúng ta tạo một đối tượng cơ bản là Article. Article là một đối tượng cơ bản gồm có title, body. Laravel cung cấp một số lệnh thông qua Artisan(Laravel’s command line tool), nó sẽ hỗ trợ chúng ta đặt file đúng theo quy định. Để tạo chúng ta chạy lệnh:

$ php artisan make:model Article -m

-m là viết tắt của -migration và nó nói rằng Artisan tạo cho chúng ta một model. Và đây là kết quả:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

Chúng ta thấy rằng:

up() vs down: là 2 function sẽ chạy khi migrate và khi rollback. $table->increments('id'): thiết lập đối tượng id là một số nguyên tự tăng. $table->timestamps(): sẽ tạo cho chúng ta một đối tượng thời gian là ngày tạo và ngày update đối tượng. Schema::dropIfExists(): xóa bảng nếu như đã tồn tại. Theo đó, chúng ta sẽ thêm một số dòng vào method up():

public function up()
{
    Schema::create('articles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->text('body');
        $table->timestamps();
    });
}

Và chạy lệnh Aritans:

$ php artisan migrate

Mặc định laravel sẽ có 2 migrate để tạo 2 bảng là: create_users_table vs create_password_resets_table. Hỗ trợ người dùng tạo đối tượng user.

Bây giờ chúng ta sẽ thêm vào model đuối tượng Article thuộc tính $fillable các trường trong bảng articles hỗ trợ khi bạn dùng Article::create vs Article::update.

class Article extends Model
{
    protected $fillable = ['title', 'body'];
}

Tạo dữ liệu mẫu(File Seeding)

Seeding: hỗ trỡ chúng ta tạo một dữ liệu mẫu, trong đó chúng ta sử dụng Faker.

$ php artisan make:seeder ArticlesTableSeeder.

class ArticlesTableSeeder extends Seeder
{
    public function run()
    {
        // Let's truncate our existing records to start from scratch.
        Article::truncate();

        $faker = \Faker\Factory::create();

        // And now, let's create a few articles in our database:
        for ($i = 0; $i < 50; $i++) {
            Article::create([
                'title' => $faker->sentence,
                'body' => $faker->paragraph,
            ]);
        }
    }
}

Để tạo dữ liệu từ file seed:

$ php artisan db:seed --class=ArticlesTableSeeder

Lặp lại quy trình trên với User:

class UsersTableSeeder extends Seeder
{
    public function run()
    {
        // Let's clear the users table first
        User::truncate();

        $faker = \Faker\Factory::create();

        // Let's make sure everyone has the same password and 
        // let's hash it before the loop, or else our seeder 
        // will be too slow.
        $password = Hash::make('toptal');

        User::create([
            'name' => 'Administrator',
            'email' => '[email protected]',
            'password' => $password,
        ]);

        // And now let's generate a few dozen users for our app:
        for ($i = 0; $i < 10; $i++) {
            User::create([
                'name' => $faker->name,
                'email' => $faker->email,
                'password' => $password,
            ]);
        }
    }
}

Để đơn giản cho mỗi lần tạo seed, chúng ta thêm vào file DatabaseSeeder với nội dung:

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(ArticlesTableSeeder::class);
        $this->call(UsersTableSeeder::class);
    }
}

Và đơn giản hơn, chúng ta chỉ cần chạy:

$ php artisan db:seed

thay vì chạy 2 lệnh: $ php artisan db:seed --class=ArticlesTableSeeder vs $ php artisan db:seed --class=UsersTableSeeder.

Routes and Controllers

Routes

Chúng ta tạo một số action cơ bản sau: create, retrieve the list, retrieve a single one, update, and delete(CRUD). trong file: routes/api.php.

Use App\Article;
 
Route::get('articles', function() {
    // If the Content-Type and Accept headers are set to 'application/json', 
    // this will return a JSON structure. This will be cleaned up later.
    return Article::all();
});
 
Route::get('articles/{id}', function($id) {
    return Article::find($id);
});

Route::post('articles', function(Request $request) {
    return Article::create($request->all);
});

Route::put('articles/{id}', function(Request $request, $id) {
    $article = Article::findOrFail($id);
    $article->update($request->all());

    return $article;
});

Route::delete('articles/{id}', function($id) {
    Article::find($id)->delete();

    return 204;
})

Các routes trong api.php sẽ bắt đầu với prefix: /api/. Nếu bạn muốn sửa prefix thì có thẻ sửa tại: RouteServiceProvider(/app/Providers/RouteServiceProvider.php).

Controller

$ php artisan make:controller ArticleController

use App\Article;
 
class ArticleController extends Controller
{
    public function index()
    {
        return Article::all();
    }
 
    public function show($id)
    {
        return Article::find($id);
    }

    public function store(Request $request)
    {
        return Article::create($request->all());
    }

    public function update(Request $request, $id)
    {
        $article = Article::findOrFail($id);
        $article->update($request->all());

        return $article;
    }

    public function delete(Request $request, $id)
    {
        $article = Article::findOrFail($id);
        $article->delete();

        return 204;
    }
}

Tại file routes/api.php chúng ta sửa lại theo controller:

Route::get('articles', '[email protected]');
Route::get('articles/{id}', '[email protected]');
Route::post('articles', '[email protected]');
Route::put('articles/{id}', '[email protected]');
Route::delete('articles/{id}', '[email protected]');

Hoặc chúng ta có thể cải thiện cấu trúc file để khi trả về trong mỗi hành động là kèm theo một response status. Mặc định khi có lỗi xảy ra chúng ta sẽ nhận được một response status: 404.

Route::get('articles', '[email protected]');
Route::get('articles/{article}', '[email protected]');
Route::post('articles', '[email protected]');
Route::put('articles/{article}', '[email protected]');
Route::delete('articles/{article}', '[email protected]');
class ArticleController extends Controller
{
    public function index()
    {
        return Article::all();
    }

    public function show(Article $article)
    {
        return $article;
    }

    public function store(Request $request)
    {
        $article = Article::create($request->all());

        return response()->json($article, 201);
    }

    public function update(Request $request, Article $article)
    {
        $article->update($request->all());

        return response()->json($article, 200);
    }

    public function delete(Article $article)
    {
        $article->delete();

        return response()->json(null, 204);
    }
}

Ý nghĩa của mỗi response status trong HTTP:

  • 200: Ok. Mã cơ bản có ý nghĩa là thành công trong hoạt động.
  • 201: Đối tượng được tạo, được dùng trong hàm store.
  • 204: Không có nội dung trả về. Hoàn thành hoạt động nhưng sẽ không trả về nội dung gì.
  • 206: Trả lại một phần nội dung, dùng khi sử dụng phân trang.
  • 400: Lỗi. Đây là lỗi cơ bản khi không vượt qua được xác nhận yêu cầu từ server.
  • 401: Unauthorized. Lỗi do yêu cầu authen.
  • 403: Forbidden. Lõi này người dùng vượt qua authen, nhưng không có quyền truy cập.
  • 404: Not found. Không tìm thấy yêu cầu tương tứng.
  • 500: Internal server error.
  • 503: Service unavailable.

Kết luận

Cám ơn bạn đã theo dõi bài dịch này của bản mình, nó là một cách cơ bản để tạo API trong laravel. Nguồn:

  1. https://www.toptal.com/laravel/restful-laravel-api-tutorial
  2. https://www.programmableweb.com/news/how-to-build-restful-apis-using-php-and-laravel/how-to/2014/08/13