1) Define Function in Python.
Sau đây chúng ta define 1 function trong python.
def my_func(my_var : str | None = None): return my_var var_1 = 10 var_2 = "10" print(my_func())
Trong đoạn mã Python trên, hàm my_func
có một đối số có tên là my_var
có kiểu dữ liệu được ghi là str | None
. Đây là kiểu gợi ý cho Python biết đối số my_var
có thể là một chuỗi (str
) hoặc là None
. Kiểu gợi ý này không buộc người lập trình phải truyền một chuỗi hay None
, nhưng nó giúp làm rõ mục tiêu của hàm và có thể hỗ trợ trong việc kiểm tra kiểu.
None = None
có nghĩa là giá trị mặc định của my_var
là None
. Khi bạn gọi my_func()
mà không truyền bất kỳ đối số nào, my_var
sẽ tự động được gán là None
.
Đoạn mã sau:print(my_func())
sẽ in ra None
, vì bạn đã gọi hàm mà không truyền giá trị cho my_var
, nên giá trị mặc định None
sẽ được sử dụng.
Các biến var_1
và var_2
không được sử dụng trong đoạn mã trên, nhưng bạn có thể sử dụng chúng bằng cách truyền vào hàm my_func
nếu muốn. Tuy nhiên, hãy chú ý rằng var_1
có kiểu dữ liệu là int
, nên nó sẽ không phù hợp với kiểu gợi ý của đối số my_var
.
2) Validate data type in python via Pydantic library.
from pydantic import BaseModel from datetime import datetime class Vietnamese(BaseModel): id: int name: str birthday: datetime vietname_1_data = {"name": "Tran Tuan Dung", "id": 100, "birthday": "2009-12-25 00:00" } vietnam_1 = Vietnamese(**vietname_1_data) print(vietnam_1)
Đoạn mã Python trên sử dụng thư viện Pydantic để định nghĩa một mô hình dữ liệu có tên là Vietnamese
. Pydantic giúp bạn định rõ kiểu dữ liệu và hệ thống sẽ tự động kiểm tra (validate) dữ liệu đầu vào để đảm bảo rằng nó phù hợp với kiểu dữ liệu đã định.
Cụ thể trong trường hợp này, mô hình Vietnamese
có ba trường:
id
: kiểuint
– số nguyên, là ID của người.name
: kiểustr
– chuỗi, là tên của người.birthday
: kiểudatetime
– thời gian, là ngày sinh của người.
Khi bạn tạo một đối tượng mới bằng cách sử dụng Vietnamese(**vietname_1_data)
, Pydantic sẽ tự động kiểm tra xem liệu dữ liệu trong từ điển vietname_1_data
có phù hợp với kiểu dữ liệu đã định trong Vietnamese
hay không.
Trong trường hợp này:
id
: 100 là một số nguyên (int
) nên không có vấn đề.name
: “Tran Tuan Dung” là một chuỗi (str
), cũng không có vấn đề.birthday
: “2009-12-25 00:00” là một chuỗi, nhưng Pydantic sẽ cố gắng tự động chuyển đổi nó thành một đối tượngdatetime
nếu có thể.
Nếu toàn bộ dữ liệu được kiểm tra (validate) thành công, đối tượng vietnam_1
sẽ được tạo và bạn có thể sử dụng nó như một đối tượng Python thông thường.
Nếu có bất kỳ trường nào không phù hợp với kiểu dữ liệu đã định, Pydantic sẽ ném ra một ngoại lệ để thông báo vấn đề.
3) Design backend for restful API on Python.
3.1) Get method with Path URL.
from fastapi import FastAPI app = FastAPI() @app.get("/items/{item_id}/action/{action_id}") def read_item(item_id: str, action_id: str): return {"item" : item_id, "action": action_id}
Ứng dụng này có một điểm đầu (endpoint) được định nghĩa thông qua decorator @app.get
.
app = FastAPI()
: Khởi tạo một đối tượng FastAPI.@app.get("/items/{item_id}/action/{action_id}")
: Định nghĩa một HTTP GET request tới URL có dạng/items/{item_id}/action/{action_id}
. Trong URL này,{item_id}
và{action_id}
là các tham số động, có nghĩa là giá trị của chúng có thể thay đổi.def read_item(item_id: str, action_id: str)
: Định nghĩa hàmread_item
với hai tham sốitem_id
vàaction_id
, cả hai đều có kiểu làstr
.
Khi bạn gửi một GET request đến URL như /items/123/action/abc
, FastAPI sẽ tự động trích xuất 123
và abc
từ URL, sau đó truyền chúng như là đối số cho hàm read_item
. Hàm này sẽ trả lại một từ điển JSON chứa item_id
và action_id
mà bạn đã cung cấp.
Ví dụ, nếu bạn gửi một GET request đến /items/123/action/abc
, ứng dụng sẽ trả lại JSON có dạng:
giờ kiểm tra bằng lệnh curl:
openvscode-server@openvscode-server-c48986987-qz8q4:~/learn-python$ curl localhost:8000/items/123/action/abc {"item":"123","action":"abc"}
3.2) Get method with query URL.
from fastapi import FastAPI app = FastAPI() data = [0, 1, 2, 3, 4, 5] @app.get("/items") def get_data(limit: int | None = 3): return data[0:limit]
Đoạn mã này sử dụng thư viện FastAPI để tạo một ứng dụng web API đơn giản với một điểm đầu (endpoint) HTTP GET tại URL /items
.
app = FastAPI()
: Khởi tạo một đối tượng FastAPI.data = [0, 1, 2, 3, 4, 5]
: Định nghĩa một danh sáchdata
chứa các số từ 0 đến 5.@app.get("/items")
: Định nghĩa một HTTP GET request tới URL/items
.def get_data(limit: int | None = 3)
: Hàmget_data
có tham sốlimit
với kiểu dữ liệu làint | None
và giá trị mặc định là3
.
Khi bạn gửi một GET request đến /items
, FastAPI sẽ gọi hàm get_data
và trả lại một phần của danh sách data
từ phần tử đầu tiên đến phần tử thứ limit
.
Nếu bạn không cung cấp tham số limit
khi gọi API (ví dụ, bạn chỉ gửi GET request đến /items
), giá trị mặc định của limit
là 3
, và API sẽ trả lại [0, 1, 2]
.
Thường bạn sẽ thấy là có dấu chấm hỏi xuất hiện “?”
Nếu bạn cung cấp tham số limit
(ví dụ, GET /items?limit=4
), thì API sẽ trả lại [0, 1, 2, 3]
.
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class User(BaseModel): username: str password: str fullname: str @app.post("/users/register") def user_register(user: User): return user
3.3) Design Post method.
openvscode-server@openvscode-server-c48986987-qz8q4:~/learn-python$ curl -X 'POST' \ 'http://127.0.0.1:8000/users/register' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "username": "your_username", "password": "your_password", "fullname": "Your Full Name" }' {"username":"your_username","password":"your_password","fullname":"Your Full Name"}
Trong lệnh này:
-X 'POST'
: Định nghĩa phương thức HTTP là POST.http://127.0.0.1:8000/users/register
: Địa chỉ của điểm đầu.-H 'accept: application/json'
: Đặt header “accept” để chỉ định rằng chúng ta muốn nhận dữ liệu trả về dưới dạng JSON.-H 'Content-Type: application/json'
: Đặt header “Content-Type” để chỉ định rằng dữ liệu gửi đi là JSON.-d '{...}'
: Dữ liệu JSON được gửi trong body của request. Bạn cần thay thếyour_username
,your_password
, vàYour Full Name
bằng các giá trị thực tế bạn muốn sử dụng.
Chú ý: Đảm bảo rằng ứng dụng FastAPI của bạn đang chạy và lắng nghe tại http://127.0.0.1:8000/
trước khi bạn chạy lệnh curl
.
4) Decrease values when responding.
Cách đâu tiên là bạn khai báo 1 model trả về và sử dụng model đó cho response
from fastapi import FastAPI, Response, status from pydantic import BaseModel from pprint import pprint app = FastAPI() class User(BaseModel): username: str password: str fullname: str class UserLogin(BaseModel): username: str password: str class UserOut(BaseModel): username: str fullname: str users = {} @app.post("/users/register", response_model=UserOut) def user_register(user: User): user_dict = user.dict() #convert to dictionary users[user_dict["username"]] = user_dict return user_dict @app.get("/users") async def user_list(): return users @app.get("/users/{username}") async def user_get(username: str): try: found_user = users[username] return found_user except KeyError: return {"message": "username not found"} @app.post("/users/login") async def user_login(credetinal: UserLogin): data = credetinal.dict() _user_name = data["username"] pprint(users) pprint(_user_name) if _user_name in users: if users[_user_name]["password"] == data["password"]: return {"message": "Login Success"} else: return {"message": "Forbidden"}
Trong ví dụ của bạn, response_model=UserOut
chỉ định rằng dữ liệu trả về từ API endpoint /users/register
sẽ tuân theo cấu trúc được định nghĩa trong lớp Pydantic UserOut
. Model UserOut
có các trường username
và fullname
, nghĩa là, dù trong users
dictionary có thêm trường password
, nó sẽ không được trả về trong phản hồi HTTP, giúp bảo mật thông tin của người dùng.
Thứ 2 là bạn sài response_model cài model cũ, response_model_exclude được sử dụng để remove các values khi response.
from fastapi import FastAPI, Response, status from pydantic import BaseModel from pprint import pprint app = FastAPI() class User(BaseModel): username: str password: str fullname: str class UserLogin(BaseModel): username: str password: str class UserOut(BaseModel): username: str fullname: str users = {} @app.post("/users/register", response_model=User, response_model_exclude={"password"}) def user_register(user: User, response: Response): user_dict = user.dict() #convert to dictionary users[user_dict["username"]] = user_dict response.status_code = status.HTTP_201_CREATED ## Hoặc để là 201 return user_dict
Một điều cần thiết là trả về status code.
Trong FastAPI, bạn có thể sử dụng tham số response: Response
để truy cập và chỉnh sửa đối tượng phản hồi HTTP một cách trực tiếp. Đối tượng Response
cho phép bạn tùy chỉnh các thuộc tính của phản hồi, bao gồm status code, headers, cookies, và nhiều thuộc tính khác.
response: Response
: Trong ví dụ của bạn,response: Response
là một tham số của hàmuser_register
. Tham số này cho phép bạn tương tác với đối tượng phản hồi HTTP một cách trực tiếp.response.status_code = status.HTTP_201_CREATED
: Ở đây, bạn đặt status code của đối tượng phản hồi là 201, tức là “Created”. Status code này là một quy ước trong RESTful APIs để thông báo rằng một nguồn tài nguyên mới đã được tạo thành công trên máy chủ.status.HTTP_201_CREATED
là chỉ một cách tiện lợi để đề cập đến số 201, giúp làm cho mã của bạn dễ đọc và hiểu hơn. Bạn cũng có thể đặtresponse.status_code = 201
nếu bạn muốn.
Khi bạn đặt response.status_code
, người dùng gửi yêu cầu đến endpoint này sẽ nhận được phản hồi với status code 201, cho họ biết rằng tài nguyên đã được tạo thành công.