Xây dựng REST API với FastAPI

Trong bài viết này, chúng ta sẽ tìm hiểu cách để xây dựng REST API server dựa trên nền tảng FastAPI của Python.

Hello World

Về cơ bản REST API là một trong những phương thức giao tiếp quan trọng nhất khi lập trình ứng dụng theo kiến trúc client-server. REST API cung cấp công cụ giao tiếp hiệu quả và an toàn cho nên nó được sử dụng rất nhiều trong các ứng dụng.

Kiến trúc client-server thông dụng

Để xây dựng REST API bằng FastAPI thì đầu tiên ta cần cài đặt package FastAPI và uvicorn từ PyPi bằng câu lệnh sau:

pip install fastapi[all] uvicorn[standard]

Sau khi đã cài đặt xong, ta thử với ví dụ về một API server với 2 endpoint như sau:

Trong đoạn code trên, ở dòng số 4 ta khởi tạo một đối tượng FastAPI server và đặt tên cho server này là "Demo REST Server". Ở dòng 6, ta sử dụng decorator app.get("/hello") để khai báo cho server biết rằng có một endpoint "http://<host>/hello" cho phương thức GET. Kể từ đó, ngay khi nhận được request với endpoint "http://<host>/hello" thì server sẽ thực thi hàm được đĩnh nghĩa ngay phía sau decorator app.get("/hello"); đó chính là hàm hello(). Chúng ta có thể thấy logic của hàm hello() rất đơn giản, khi nhận được request nó sẽ trả về JSON với nội dung:

{ "message": "Hello, World" }

Tương tự ở dòng 10 ta có một GET endpoint khác. Tuy nhiên lần này ta thấy có thêm tham số trong đường dẫn (user_id). Tham số này sẽ được truyền trực tiếp thông qua tên biến của hàm get_user.

FastAPI là một ASGI app framework, do đó để chạy ứng dụng được tạo bằng FastAPI thì chúng ta có thể sử dụng bất kỳ ASGI web server nào tương thích với Python. Ở đây chúng ta sẽ sử dụng Uvicorn. Để chạy ứng dụng FastAPI bằng Uvicorn, đặt đoạn code trên vào file fastapi_helloworld.py và dùng lệnh sau:

uvicorn fastapi_helloworld:app --port 5000

Khi đó, một server REST API sẽ được mở tại port 5000. Chúng ta có thể mở http://localhost:5000/docs hoặc http://localhost:5000/redocs để xem document của API.

Ngoài ra, ta có thể sử dụng curl để test thử API ngay tại localhost, ví dụ:

curl --location --request GET 'http://127.0.0.1:5000/hello'
# response: { "message": "Hello, World" }

curl --location --request GET 'http://127.0.0.1:5000/get_user/123'
# response: { "message": "You requested data of 123" }

Data Model

FastAPI hỗ trợ lập trình viên định nghĩa data model cho cả request parameter và response thông qua pydantic. Dưới đây là một ví dụ khi sử dụng pydantic để định nghĩa data model Item cho request parameter.

Trong đoạn code trên ta sử dụng phương thức PUT thay vì GET. Tương tự như GET, hàm update_item cũng sẽ nhận tham số thông qua đường dẫn url là item_id, ngoài ra nó cũng nhận thêm tham số item thông qua request body (tham số item trong request body phải đúng định dạng khi serialize của data model Item, trong trường hợp này là JSON).

curl --location --request PUT 'http://127.0.0.1:5000/update/001' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "Iphone 14 Pro Max",
    "price": 32500000,
    "quantity": 500
}'

# respone: {
                "item_id": 1,
                "item_name": "Iphone 14 Pro Max",
                "item_price": 32500000.0,
                "item_quantity": 500
           }

Upload File

Một tác vụ hay sử dụng của API đó là upload file, đối với FastAPI ta hiện thực tác vụ này thông qua phương thức POST như sau:

Cũng như những framework khác, ta sẽ sử dụng form-data/multipart để upload dữ liệu. Hai tham số file_id và file sẽ được lấy ra từ request body thông qua tên tham số tương tự như những phương thức GET và PUT.

Ví dụ sử dụng curl để upload file lên server, lưu ý thay đổi đường dẫn của file trong máy local.

curl --location --request POST 'http://127.0.0.1:5000/upload' \
--form 'file=@"/home/vndee/Desktop/test001.jpg"' \
--form 'file_id="001"'

# response: {
                "file_id": 1,
                "file_name": "test001.jpg",
                "file_type": "image/jpeg"
            }

Full Request Info

Trong trường hợp cần sử dụng rất nhiều thông tin trong request, bao gồm cả headers thì chúng ta có thể lấy trực tiếp thông tin của toàn bộ request thông qua class Request được cung cấp sẵn bởi FastAPI:

Ví dụ trên sẽ trả về thông tin headers của request như sau:

curl --location --request GET 'http://127.0.0.1:5000/view_request_info'

# response: {
                "user-agent": "PostmanRuntime/7.29.2",
                "accept": "*/*",
                "postman-token": "4d6f81a0-6d30-4c10-bbce-c1a78f7fdddd",
                "host": "127.0.0.1:5000",
                "accept-encoding": "gzip, deflate, br",
                "connection": "keep-alive"
            }

Chúng ta thường sử dụng cách này trong khi lập trình middleware của ứng dụng. Ví dụ ta có middleware để kiểm tra API_KEY của request như bên dưới:

Middleware này sẽ thực hiện kiểm tra apiKey trong headers của bất kỳ request nào đến API server, nếu có bất kỳ request nào không có hoặc không đúng apiKey thì sẽ bị từ chối ngay lập tức.

Ví dụ:

curl --location --request GET 'http://127.0.0.1:5000/hello' \
--header 'apiKey: this_is_my_key'
# response: { "message": "Hello, World" }

curl --location --request GET 'http://127.0.0.1:5000/hello' \
--header 'apiKey: this_is_my_bad_key'
# response { "message": "Your key is mismatched" }

Trên đây là một vài ví dụ nhỏ về cách xây dựng REST API bằng Python FastAPI. FastAPI là một framework tinh gọn và dễ sử dụng cho nên đang ngày càng được nhiều doanh nghiệp và tổ chức sử dụng trong các dự án của mình. Bạn đọc có thể tìm đọc thêm tài liệu đầy đủ của framework này tại đây: https://fastapi.tiangolo.com/