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ượngdatetimenế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_itemvới hai tham sốitem_idvà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áchdatachứ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_datacó tham sốlimitvới kiểu dữ liệu làint | Nonevà 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 Namebằ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: Responselà 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_CREATEDlà 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 = 201nế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.