
ในโลกของการพัฒนาซอฟต์แวร์ยุคใหม่ การสร้าง API (Application Programming Interface) ที่รวดเร็ว มีประสิทธิภาพ และดูแลรักษาง่าย คือหัวใจสำคัญในการเชื่อมโยงบริการและแอปพลิเคชันต่างๆ เข้าด้วยกันครับ และเมื่อพูดถึงการสร้าง RESTful API ด้วย Python ในปัจจุบัน หนึ่งในเครื่องมือที่กำลังมาแรงและได้รับความนิยมอย่างก้าวกระโดดก็คือ FastAPI นี่แหละครับ
FastAPI ไม่ได้เป็นเพียงแค่ Web Framework ทั่วไป แต่เป็น Framework ที่ถูกออกแบบมาเพื่อความเร็ว ทั้งความเร็วในการพัฒนาและประสิทธิภาพในการทำงานจริง พร้อมด้วยคุณสมบัติเด่นมากมาย เช่น การรองรับ Asynchronous Programming (async/await) ตั้งแต่แก่น การสร้างเอกสาร API อัตโนมัติ (Swagger UI และ ReDoc) และการใช้ Python Type Hints เพื่อการตรวจสอบข้อมูลที่มีประสิทธิภาพ วันนี้ SiamLancard.com จะพาทุกท่านดำดิ่งสู่โลกของ FastAPI ตั้งแต่การเตรียมความพร้อมไปจนถึงการสร้าง REST API ที่ครบวงจร พร้อมตัวอย่างโค้ดที่ใช้งานได้จริง เพื่อให้คุณสามารถนำไปประยุกต์ใช้ในโปรเจกต์ของคุณได้อย่างมั่นใจครับ
สารบัญ
- บทนำ: ทำไมต้อง FastAPI?
- เตรียมความพร้อมก่อนเริ่มต้น
- พื้นฐาน REST API ที่ควรรู้
- เริ่มต้นสร้าง API แรกด้วย FastAPI (Hello World)
- การจัดการ Path Parameters
- การจัดการ Query Parameters
- การใช้ Request Body ด้วย Pydantic (POST, PUT, PATCH)
- Validation และ Error Handling
- การทำ Dependency Injection
- การสร้างเอกสาร API อัตโนมัติ (Swagger UI และ ReDoc)
- เปรียบเทียบ FastAPI กับ Web Frameworks อื่นๆ
- ข้อควรพิจารณาในการนำ FastAPI ไปใช้งานจริง
- คำถามที่พบบ่อย (FAQ)
- สรุปและ Call-to-Action
บทนำ: ทำไมต้อง FastAPI?
ก่อนที่เราจะลงมือโค้ดกัน มาทำความเข้าใจกันก่อนครับว่าอะไรคือสิ่งที่ทำให้ FastAPI โดดเด่นและเป็นที่น่าจับตามองในหมู่ Web Frameworks ของ Python ครับ
ความเร็วและประสิทธิภาพ
FastAPI สร้างขึ้นบน Starlette สำหรับส่วนของ Web และ Uvicorn สำหรับ ASGI server ทำให้มันสามารถจัดการกับ requests ได้อย่างรวดเร็วมาก โดยเฉพาะอย่างยิ่งเมื่อเทียบกับ Frameworks แบบ WSGI ดั้งเดิมอย่าง Flask หรือ Django ครับ
Python Type Hints เพื่อการพัฒนาที่แม่นยำ
จุดเด่นที่สุดของ FastAPI คือการใช้ Python Type Hints อย่างเต็มรูปแบบ ซึ่งช่วยให้ IDE ของคุณสามารถให้คำแนะนำ (autocomplete) และตรวจสอบข้อผิดพลาด (type checking) ได้ดีขึ้น ทำให้โค้ดสะอาดขึ้น ลดข้อผิดพลาด และเพิ่มความเร็วในการพัฒนาอย่างมหาศาลครับ
เอกสาร API อัตโนมัติ (Swagger UI / ReDoc)
FastAPI สามารถสร้างเอกสาร API แบบ interactive (Swagger UI) และแบบ Redoc ให้คุณได้โดยอัตโนมัติจากโค้ดที่คุณเขียน ทำให้คุณไม่ต้องเสียเวลามานั่งเขียนเอกสาร API แยกต่างหากอีกต่อไป ซึ่งช่วยลดภาระงานและมั่นใจได้ว่าเอกสาร API ของคุณจะอัปเดตอยู่เสมอครับ
ความง่ายในการเรียนรู้และใช้งาน
ด้วยโครงสร้างที่เรียบง่ายและเป็นธรรมชาติ FastAPI จึงมี Learning Curve ที่ไม่สูงนักสำหรับนักพัฒนา Python ที่คุ้นเคยกับ Frameworks อื่นๆ มาบ้างแล้วครับ
Asynchronous Programming (async/await)
FastAPI ถูกสร้างมาเพื่อรองรับ Asynchronous Programming โดยเฉพาะ ทำให้คุณสามารถเขียนโค้ดที่จัดการกับ I/O-bound operations (เช่น การเรียกฐานข้อมูล การเรียก API อื่นๆ) ได้อย่างมีประสิทธิภาพสูง ไม่ต้องรอให้แต่ละ request ทำงานเสร็จทีละอันครับ
เตรียมความพร้อมก่อนเริ่มต้น
ก่อนที่เราจะเริ่มสร้าง API ด้วย FastAPI เรามาเตรียมเครื่องมือที่จำเป็นกันก่อนนะครับ
ติดตั้ง Python
แน่นอนครับว่าคุณต้องมี Python ติดตั้งอยู่ในเครื่องก่อน แนะนำให้ใช้ Python เวอร์ชัน 3.7 ขึ้นไปครับ คุณสามารถดาวน์โหลดได้จาก เว็บไซต์ทางการของ Python ครับ
สร้าง Virtual Environment
การใช้ Virtual Environment เป็นสิ่งสำคัญในการจัดการ Dependencies ของโปรเจกต์ต่างๆ เพื่อไม่ให้เกิดความขัดแย้งกันครับ
python3 -m venv venv
source venv/bin/activate # สำหรับ macOS/Linux
venv\Scripts\activate # สำหรับ Windows
หลังจากรันคำสั่งข้างต้น คุณจะเห็น (venv) นำหน้าบรรทัดคำสั่ง ซึ่งหมายความว่าคุณกำลังอยู่ใน Virtual Environment แล้วครับ
ติดตั้ง FastAPI และ Uvicorn
เมื่ออยู่ใน Virtual Environment แล้ว เราก็สามารถติดตั้ง FastAPI และ Uvicorn ได้เลยครับ
pip install fastapi "uvicorn[standard]"
fastapiคือตัว Framework หลักuvicorn[standard]คือ ASGI server ที่ FastAPI ใช้ในการรันแอปพลิเคชัน ([standard]จะติดตั้ง Libraries เพิ่มเติมที่จำเป็น เช่นhttptoolsและwatchgodเพื่อประสิทธิภาพที่ดีขึ้นและ Hot-reloading)
พื้นฐาน REST API ที่ควรรู้
ก่อนจะลุยโค้ด เรามาทบทวนหลักการพื้นฐานของ REST API กันเล็กน้อยนะครับ เพื่อให้เข้าใจแนวคิดเบื้องหลังการออกแบบ API ของเราครับ
Resource (ทรัพยากร)
ใน REST API ทุกสิ่งคือ “ทรัพยากร” (Resource) ครับ เช่น ผู้ใช้งาน (User), สินค้า (Product), คำสั่งซื้อ (Order) เป็นต้น ทรัพยากรแต่ละชนิดจะถูกระบุด้วย URI (Uniform Resource Identifier) ที่ไม่ซ้ำกันครับ เช่น /items หรือ /users/123
HTTP Methods (GET, POST, PUT, DELETE, PATCH)
เราใช้ HTTP Methods เพื่อระบุการกระทำที่เราต้องการทำกับทรัพยากรนั้นๆ ครับ:
- GET: ใช้สำหรับดึงข้อมูลทรัพยากร (Read)
- POST: ใช้สำหรับสร้างทรัพยากรใหม่ (Create)
- PUT: ใช้สำหรับอัปเดตข้อมูลทรัพยากรทั้งหมด (Update/Replace)
- DELETE: ใช้สำหรับลบทรัพยากร (Delete)
- PATCH: ใช้สำหรับอัปเดตข้อมูลบางส่วนของทรัพยากร (Partial Update)
HTTP Status Codes
Server จะส่ง HTTP Status Codes กลับมาเพื่อบอกสถานะของ Request นั้นๆ ครับ เช่น:
200 OK: Request สำเร็จ201 Created: ทรัพยากรถูกสร้างสำเร็จ204 No Content: Request สำเร็จ แต่ไม่มีข้อมูลที่จะส่งกลับ (มักใช้กับการลบ)400 Bad Request: Request ไม่ถูกต้อง401 Unauthorized: ไม่ได้รับอนุญาต (ไม่ได้ล็อกอิน)403 Forbidden: ไม่มีสิทธิ์เข้าถึง (ล็อกอินแล้วแต่ไม่มีสิทธิ์)404 Not Found: ไม่พบทรัพยากร500 Internal Server Error: ข้อผิดพลาดฝั่ง Server
Statelessness
หลักการสำคัญของ REST คือแต่ละ Request จาก Client ไปยัง Server ควรมีข้อมูลทั้งหมดที่จำเป็นในการประมวลผล Request นั้นๆ Server จะไม่เก็บ “สถานะ” ของ Client ระหว่าง Request ครับ
เริ่มต้นสร้าง API แรกด้วย FastAPI (Hello World)
ได้เวลาลงมือโค้ดกันแล้วครับ! มาสร้าง API ง่ายๆ ที่คืนค่า “Hello World” กันก่อนครับ
โค้ดตัวอย่าง Hello World
สร้างไฟล์ชื่อ main.py ในโปรเจกต์ของคุณ และเพิ่มโค้ดต่อไปนี้ครับ
# main.py
from fastapi import FastAPI
# สร้าง Instance ของ FastAPI Application
app = FastAPI()
# กำหนด Path Operation สำหรับ HTTP GET Request ที่ Path "/"
@app.get("/")
async def read_root():
"""
API endpoint สำหรับ Path หลักที่จะคืนค่าข้อความ "Hello World"
"""
return {"message": "Hello World"}
มาดูกันครับว่าแต่ละส่วนทำอะไรบ้าง:
from fastapi import FastAPI: นำเข้าคลาสFastAPIapp = FastAPI(): สร้าง Object ของแอปพลิเคชัน FastAPI ของเรา@app.get("/"): นี่คือ Decorator ที่บอก FastAPI ว่าฟังก์ชันread_rootด้านล่างนี้ควรถูกรันเมื่อมีการเรียก HTTP GET Request ไปยัง Path"/"ครับasync def read_root():: นี่คือฟังก์ชัน Path Operation ของเรา ใช้async defเพราะ FastAPI รองรับ Asynchronous Operations ครับ ฟังก์ชันนี้จะคืนค่า Python dictionary ซึ่ง FastAPI จะแปลงเป็น JSON Response ให้โดยอัตโนมัติครับ
การรัน Uvicorn
เปิด Terminal (หรือ Command Prompt) ใน Virtual Environment ที่คุณสร้างไว้ และรันคำสั่งต่อไปนี้ครับ
uvicorn main:app --reload
uvicorn: ชื่อของ ASGI server ที่เราติดตั้งไปmain:app: บอก Uvicorn ว่าให้หา Object ที่ชื่อappในไฟล์main.py--reload: เป็น Flag ที่มีประโยชน์มากในการพัฒนาครับ มันจะทำให้ Uvicorn ตรวจจับการเปลี่ยนแปลงในโค้ดของคุณและรีโหลด Server โดยอัตโนมัติเมื่อคุณบันทึกไฟล์ครับ
คุณควรจะเห็น Output ประมาณนี้ครับ:
INFO: Will watch for changes in these directories: ['/path/to/your/project']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [xxxxx] using stat reload
INFO: Started server process [xxxxx]
INFO: Waiting for application startup.
INFO: Application startup complete.
แสดงว่า Server ของคุณกำลังทำงานอยู่ที่ http://127.0.0.1:8000 แล้วครับ
ทดสอบ API
เปิด Web Browser ของคุณแล้วไปที่ http://127.0.0.1:8000 คุณจะเห็น JSON Response: {"message": "Hello World"} ครับ
เยี่ยมไปเลยครับ! คุณได้สร้าง REST API ตัวแรกด้วย FastAPI สำเร็จแล้วครับ
การจัดการ Path Parameters
Path Parameters คือค่าที่เราส่งไปใน URL เพื่อระบุทรัพยากรเฉพาะ เช่น /items/5 เพื่อดึงข้อมูล Item ที่มี ID เป็น 5 ครับ
ตัวอย่างโค้ด Path Parameters
เพิ่มโค้ดต่อไปนี้ในไฟล์ main.py ของคุณ:
# main.py (เพิ่มจากโค้ดเดิม)
# ... (โค้ดเดิม) ...
@app.get("/items/{item_id}")
async def read_item(item_id: int):
"""
API endpoint สำหรับดึงข้อมูล Item ด้วย ID.
item_id: ID ของ Item ที่ต้องการดึงข้อมูล.
"""
return {"item_id": item_id}
ในโค้ดนี้:
/items/{item_id}: เราใช้{}เพื่อระบุ Path Parameter ชื่อitem_iditem_id: int: FastAPI จะตรวจจับ Path Parameter นี้และส่งค่าเข้ามาในฟังก์ชันread_itemโดยอัตโนมัติ และที่สำคัญคือเราใช้ Type Hint: intเพื่อบอกว่าitem_idควรจะเป็น integer ครับ FastAPI จะทำการตรวจสอบข้อมูล (data validation) ให้โดยอัตโนมัติ ถ้าคุณลองส่งค่าที่ไม่ใช่ integer เช่น/items/abcคุณจะได้ Error Response กลับมาครับ
ทดสอบ:
- ไปที่
http://127.0.0.1:8000/items/5คุณจะได้{"item_id": 5} - ไปที่
http://127.0.0.1:8000/items/100คุณจะได้{"item_id": 100} - ลองไปที่
http://127.0.0.1:8000/items/abcคุณจะได้ Error Response (Status Code 422 Unprocessable Entity)
การจัดการ Query Parameters
Query Parameters คือค่าที่เราส่งไปใน URL หลังเครื่องหมาย ? เพื่อกรองข้อมูล จัดเรียง หรือจำกัดผลลัพธ์ เช่น /items?skip=0&limit=10 ครับ
ตัวอย่างโค้ด Query Parameters
เพิ่มโค้ดต่อไปนี้ในไฟล์ main.py ของคุณ:
# main.py (เพิ่มจากโค้ดเดิม)
# ... (โค้ดเดิม) ...
@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
"""
API endpoint สำหรับดึงข้อมูล Item โดยรองรับ Query Parameters สำหรับการแบ่งหน้า.
skip: จำนวน Item ที่จะข้ามไป (Offset).
limit: จำนวน Item สูงสุดที่จะดึงกลับมา.
"""
return {"skip": skip, "limit": limit}
ในโค้ดนี้:
skip: int = 0, limit: int = 10: เรากำหนดพารามิเตอร์ของฟังก์ชันพร้อมกับ Type Hints และค่า Default ครับ ถ้า Client ไม่ได้ส่งค่าskipหรือlimitมา FastAPI จะใช้ค่า Default ที่เรากำหนดไว้
ทดสอบ:
- ไปที่
http://127.0.0.1:8000/items/คุณจะได้{"skip": 0, "limit": 10}(ใช้ค่า Default) - ไปที่
http://127.0.0.1:8000/items/?skip=5&limit=20คุณจะได้{"skip": 5, "limit": 20} - ลองไปที่
http://127.0.0.1:8000/items/?skip=abcคุณจะได้ Error Response
ข้อสังเกต: Path Operation สำหรับ
/items/{item_id}และ/items/จะไม่เกิดความขัดแย้งกัน เพราะ FastAPI จะจับคู่กับ Path ที่เจาะจงกว่าก่อนเสมอครับ (คือ/items/{item_id})
การใช้ Request Body ด้วย Pydantic (POST, PUT, PATCH)
สำหรับการสร้างหรืออัปเดตทรัพยากร เรามักจะต้องส่งข้อมูลจำนวนมาก ซึ่งไม่เหมาะกับการส่งผ่าน Path หรือ Query Parameters ครับ เราจะใช้ Request Body (มักจะเป็น JSON) แทน โดย FastAPI จะใช้ Library ที่ชื่อว่า Pydantic ในการจัดการและตรวจสอบข้อมูลใน Request Body ครับ
Pydantic Models: หัวใจของการจัดการข้อมูล
Pydantic ช่วยให้เราสามารถกำหนดโครงสร้างข้อมูลที่เราคาดหวังจะได้รับ (หรือส่งออก) ได้อย่างชัดเจน โดยใช้ Python Type Hints ครับ
สร้าง Pydantic Model สำหรับ Item ของเราครับ:
# main.py (เพิ่มจากโค้ดเดิม)
from typing import Optional
from pydantic import BaseModel
# ... (โค้ดเดิม) ...
class Item(BaseModel):
name: str
description: Optional[str] = None # Optional หมายถึงมีหรือไม่มีก็ได้ และกำหนดค่า Default เป็น None
price: float
tax: Optional[float] = None
# ... (โค้ดเดิม) ...
ใน Item Model:
name: str: กำหนดว่าnameต้องเป็น stringdescription: Optional[str] = None: กำหนดว่าdescriptionเป็น string ก็ได้ หรือจะไม่มีก็ได้ (เป็นNone)price: float: กำหนดว่าpriceต้องเป็น floattax: Optional[float] = None: เช่นเดียวกับdescription
Pydantic จะทำการตรวจสอบข้อมูลให้โดยอัตโนมัติ ถ้าข้อมูลที่ส่งมาไม่ตรงตาม Model ที่กำหนด ก็จะคืนค่า Error กลับไปครับ
ตัวอย่างการสร้าง CRUD API สำหรับ Item
เราจะสร้าง In-memory Database ง่ายๆ โดยใช้ Python dictionary เพื่อเก็บข้อมูล Item ครับ
# main.py (เพิ่มจากโค้ดเดิม)
# ... (imports และ Item Model เดิม) ...
# In-memory database (สำหรับตัวอย่างนี้)
fake_db = {}
next_item_id = 1
@app.get("/")
async def read_root():
return {"message": "Welcome to FastAPI Item API!"}
# ... (Path และ Query Parameters เดิม) ...
ตอนนี้เรามาสร้าง Path Operations สำหรับ CRUD (Create, Read, Update, Delete) กันครับ
POST: สร้าง Item ใหม่
# main.py (เพิ่มโค้ดต่อไปนี้)
# ... (โค้ดเดิม) ...
@app.post("/items/", response_model=Item, status_code=201)
async def create_item(item: Item):
"""
API endpoint สำหรับสร้าง Item ใหม่.
รับข้อมูล Item ใน Request Body และบันทึกลงในฐานข้อมูล.
"""
global next_item_id
item_id = next_item_id
fake_db[item_id] = item.dict() # แปลง Pydantic Model เป็น dictionary
fake_db[item_id]["id"] = item_id # เพิ่ม ID เข้าไปในข้อมูล
next_item_id += 1
return fake_db[item_id]
@app.post("/items/", ...): ใช้ Decorator สำหรับ HTTP POST Requestresponse_model=Item: FastAPI จะใช้ Pydantic ModelItemในการตรวจสอบข้อมูลและแปลง Response ที่ส่งกลับไปให้ตรงตามโครงสร้างของItemครับstatus_code=201: กำหนดให้ API นี้ส่ง HTTP Status Code 201 Created เมื่อสำเร็จasync def create_item(item: Item): FastAPI จะรับ Request Body มาและแปลงเป็น Object ของItemModel ให้เราโดยอัตโนมัติ พร้อมทั้งตรวจสอบข้อมูลให้ด้วยครับ
ทดสอบ (ใช้เครื่องมืออย่าง Postman, Insomnia หรือ Swagger UI):
- Method: POST
- URL:
http://127.0.0.1:8000/items/ - Body (Raw, JSON):
{ "name": "Laptop", "description": "Powerful gaming laptop", "price": 1200.0, "tax": 10.0 } - Response: คุณจะได้ข้อมูล Item ที่ถูกสร้างขึ้นพร้อม ID และ Status Code 201 ครับ
GET: ดึงข้อมูล Item ทั้งหมด
เรามาปรับปรุง Path Operation read_items เดิมให้ดึงข้อมูลจาก fake_db จริงๆ ครับ
# main.py (ปรับปรุงโค้ด read_items)
# ... (โค้ดเดิม) ...
# ปรับปรุง read_items เดิม
@app.get("/items/", response_model=list[Item]) # ใช้ list[Item] เพื่อบอกว่าคืนค่าเป็นลิสต์ของ Item
async def read_items(skip: int = 0, limit: int = 10):
"""
API endpoint สำหรับดึงข้อมูล Item ทั้งหมด โดยรองรับการแบ่งหน้า.
"""
# ดึงค่าจาก fake_db โดยใช้ skip และ limit
items_list = list(fake_db.values())
return items_list[skip : skip + limit]
ทดสอบ:
- ไปที่
http://127.0.0.1:8000/items/คุณจะเห็นรายการ Item ที่คุณสร้างไว้ครับ
GET: ดึงข้อมูล Item ตาม ID
ปรับปรุง Path Operation read_item เดิมให้ดึงข้อมูลจาก fake_db และเพิ่มการจัดการกรณีไม่พบข้อมูลครับ
# main.py (ปรับปรุงโค้ด read_item)
# ... (โค้ดเดิม) ...
from fastapi import HTTPException, status # เพิ่ม HTTPException และ status
# ปรับปรุง read_item เดิม
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: int):
"""
API endpoint สำหรับดึงข้อมูล Item ด้วย ID.
หากไม่พบ Item จะส่งคืน 404 Not Found.
"""
if item_id not in fake_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
return fake_db[item_id]
ตอนนี้ถ้า item_id ที่ร้องขอไม่พบใน fake_db มันจะส่ง HTTP 404 Not Found กลับไปครับ
ทดสอบ:
- ไปที่
http://127.0.0.1:8000/items/1(สมมติว่า ID 1 มีอยู่) คุณจะได้ข้อมูล Item นั้น - ไปที่
http://127.0.0.1:8000/items/999(สมมติว่า ID 999 ไม่มีอยู่) คุณจะได้ Status Code 404 พร้อมข้อความ{"detail": "Item not found"}
PUT: อัปเดตข้อมูล Item
สำหรับการอัปเดตข้อมูล เราจะใช้ HTTP PUT ครับ
# main.py (เพิ่มโค้ดต่อไปนี้)
# ... (โค้ดเดิม) ...
@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: int, item: Item):
"""
API endpoint สำหรับอัปเดตข้อมูล Item ทั้งหมดด้วย ID.
รับข้อมูล Item ใหม่ใน Request Body และแทนที่ข้อมูลเดิม.
"""
if item_id not in fake_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
fake_db[item_id] = item.dict()
fake_db[item_id]["id"] = item_id # ตรวจสอบให้แน่ใจว่า ID ยังคงอยู่
return fake_db[item_id]
ทดสอบ:
- Method: PUT
- URL:
http://127.0.0.1:8000/items/1(สมมติว่า ID 1 มีอยู่) - Body (Raw, JSON):
{ "name": "Super Laptop Pro", "description": "The ultimate gaming and work machine.", "price": 1500.0, "tax": 15.0 } - Response: คุณจะได้ข้อมูล Item ที่ถูกอัปเดตแล้ว
- ลอง GET
http://127.0.0.1:8000/items/1เพื่อยืนยันการเปลี่ยนแปลงครับ
DELETE: ลบข้อมูล Item
สำหรับการลบข้อมูล เราจะใช้ HTTP DELETE ครับ
# main.py (เพิ่มโค้ดต่อไปนี้)
# ... (โค้ดเดิม) ...
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(item_id: int):
"""
API endpoint สำหรับลบ Item ด้วย ID.
หากลบสำเร็จจะส่งคืน 204 No Content.
"""
if item_id not in fake_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
del fake_db[item_id]
return # ไม่ต้องคืนค่าอะไรกลับไปสำหรับ 204 No Content
status_code=status.HTTP_204_NO_CONTENT: สำหรับการลบที่สำเร็จ มักจะส่ง Status Code 204 กลับไปครับ ซึ่งหมายถึงไม่มีเนื้อหาใดๆ ใน Response Body ครับ
ทดสอบ:
- Method: DELETE
- URL:
http://127.0.0.1:8000/items/1(สมมติว่า ID 1 มีอยู่) - Response: คุณจะได้ Status Code 204 No Content และไม่มี Body กลับมา
- ลอง GET
http://127.0.0.1:8000/items/1อีกครั้ง คุณจะได้ Status Code 404 เพราะ Item ถูกลบไปแล้วครับ
Validation และ Error Handling
FastAPI มีกลไกการตรวจสอบข้อมูลและจัดการข้อผิดพลาดที่ดีเยี่ยมครับ
Pydantic Validation
ดังที่เราได้เห็นไปแล้ว Pydantic จะทำการตรวจสอบข้อมูลใน Request Body หรือ Path/Query Parameters โดยอัตโนมัติ หากข้อมูลไม่ตรงตาม Type Hint หรือ Pydantic Model ที่กำหนด FastAPI จะคืนค่า Error Response ที่มี Status Code 422 Unprocessable Entity โดยอัตโนมัติ พร้อมรายละเอียดของ Error นั้นๆ ครับ
HTTPException
เมื่อเราต้องการส่ง Error Response แบบกำหนดเอง เช่น 404 Not Found หรือ 403 Forbidden เราสามารถใช้ HTTPException ได้ครับ
# main.py (ตัวอย่างจาก read_item)
from fastapi import HTTPException, status
# ... (โค้ดเดิม) ...
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: int):
if item_id not in fake_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
return fake_db[item_id]
ในตัวอย่างนี้ ถ้า item_id ไม่พบใน fake_db เราจะ raise HTTPException โดยระบุ status_code และ detail (ข้อความ Error) ที่ต้องการครับ
ตัวอย่างโค้ด Error Handling
FastAPI ยังช่วยให้เราสามารถกำหนด Custom Exception Handlers ได้อีกด้วย แต่สำหรับบทความนี้ เราจะเน้นที่การใช้ HTTPException ซึ่งเป็นวิธีที่ง่ายและครอบคลุมการใช้งานส่วนใหญ่แล้วครับ
# main.py (ตัวอย่างเพิ่มเติม)
# ... (โค้ดเดิม) ...
# ตัวอย่างการใช้ HTTPException กับข้อจำกัดเพิ่มเติม
@app.get("/users/{user_id}")
async def get_user(user_id: int):
if user_id < 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="User ID cannot be negative"
)
# สมมติว่าดึงข้อมูลจาก DB
if user_id != 1: # สมมติว่ามีแค่ user_id 1
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with ID {user_id} not found"
)
return {"user_id": user_id, "name": "John Doe"}
ด้วย HTTPException คุณสามารถควบคุมการส่ง Error Response ได้อย่างยืดหยุ่นครับ
การทำ Dependency Injection
Dependency Injection (DI) เป็นแนวคิดที่ทรงพลังใน FastAPI ที่ช่วยให้โค้ดของคุณ Modular, ทดสอบง่าย และนำกลับมาใช้ใหม่ได้ง่ายขึ้นครับ โดย FastAPI ใช้ฟังก์ชัน Depends ในการจัดการ DI
แนวคิดคือ คุณสามารถกำหนด “Dependencies” (เช่น การตรวจสอบสิทธิ์, การเชื่อมต่อฐานข้อมูล, การดึงค่าจาก Header) เป็นฟังก์ชันแยกต่างหาก แล้วให้ FastAPI “inject” ผลลัพธ์ของฟังก์ชันเหล่านั้นเข้าไปใน Path Operation ของคุณครับ
ตัวอย่างการใช้งาน Depends (API Key Authentication อย่างง่าย)
สมมติว่าเราต้องการให้บาง API Endpoint ต้องมีการตรวจสอบ API Key ครับ
# main.py (เพิ่มโค้ดต่อไปนี้)
# ... (โค้ดเดิม) ...
from fastapi import Header, Depends, HTTPException, status
async def get_api_key(api_key: str = Header(...)):
"""
Dependency เพื่อตรวจสอบ API Key จาก X-API-Key Header.
"""
if api_key != "supersecretkey": # API Key ที่ถูกต้อง
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid API Key")
return api_key
@app.get("/protected-items/", dependencies=[Depends(get_api_key)], response_model=list[Item])
async def read_protected_items(skip: int = 0, limit: int = 10):
"""
API endpoint ที่ต้องใช้ API Key ในการเข้าถึง เพื่อดึงข้อมูล Item.
"""
items_list = list(fake_db.values())
return items_list[skip : skip + limit]
@app.get("/protected-items/{item_id}", dependencies=[Depends(get_api_key)], response_model=Item)
async def read_protected_item(item_id: int):
"""
API endpoint ที่ต้องใช้ API Key ในการเข้าถึง เพื่อดึงข้อมูล Item ตาม ID.
"""
if item_id not in fake_db:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
return fake_db[item_id]
ในตัวอย่างนี้:
async def get_api_key(api_key: str = Header(...)): นี่คือฟังก์ชัน Dependency ของเรา มันคาดหวังว่าจะมี Header ชื่อX-API-Keyซึ่งเป็น string ครับ (Header(...)หมายถึง Header นี้จำเป็นต้องมี)- ถ้า
api_keyไม่ตรงกับ"supersecretkey"มันจะ raiseHTTPException403 Forbidden @app.get("/protected-items/", dependencies=[Depends(get_api_key)], ...): เราใช้พารามิเตอร์dependenciesใน Decorator เพื่อบอก FastAPI ว่าก่อนจะรันฟังก์ชันread_protected_itemsให้รันget_api_keyก่อนครับ
ทดสอบ:
- ลองเรียก
http://127.0.0.1:8000/protected-items/โดยไม่มี HeaderX-API-Keyคุณจะได้ Status Code 403 - ลองเรียก
http://127.0.0.1:8000/protected-items/โดยเพิ่ม HeaderX-API-Key: supersecretkeyคุณจะสามารถดึงข้อมูลได้ครับ
Dependency Injection เป็นคุณสมบัติที่ทรงพลังมาก และสามารถนำไปประยุกต์ใช้ได้หลากหลาย เช่น การจัดการ Database Session, การตรวจสอบสิทธิ์ของผู้ใช้, หรือการดึงค่า Configuration ครับ
การสร้างเอกสาร API อัตโนมัติ (Swagger UI และ ReDoc)
หนึ่งในคุณสมบัติที่น่าทึ่งที่สุดของ FastAPI คือความสามารถในการสร้างเอกสาร API แบบ Interactive โดยอัตโนมัติครับ
- Swagger UI: เมื่อ Server ของคุณทำงานอยู่ ให้ไปที่
http://127.0.0.1:8000/docsคุณจะเห็นหน้า UI ที่สวยงาม แสดงรายการ API Endpoints ทั้งหมดที่คุณสร้างไว้ พร้อมรายละเอียดของ Path Parameters, Query Parameters, Request Body และ Response Models คุณสามารถทดสอบ API ได้โดยตรงจากหน้านี้ด้วยครับ - ReDoc: อีกทางเลือกหนึ่งสำหรับเอกสาร API คือ ReDoc ซึ่งเน้นการอ่านง่ายและสวยงาม คุณสามารถเข้าถึงได้ที่
http://127.0.0.1:8000/redoc
เอกสารเหล่านี้ถูกสร้างขึ้นโดยอัตโนมัติจากโค้ดของคุณและ Type Hints ที่คุณใช้ ทำให้คุณประหยัดเวลาในการทำเอกสารและมั่นใจได้ว่าเอกสารของคุณจะอัปเดตอยู่เสมอครับ
เปรียบเทียบ FastAPI กับ Web Frameworks อื่นๆ
เพื่อช่วยให้คุณเห็นภาพชัดเจนขึ้นว่า FastAPI มีจุดเด่นอย่างไรเมื่อเทียบกับ Web Frameworks อื่นๆ ใน Python ที่ได้รับความนิยม ผมได้เตรียมตารางเปรียบเทียบง่ายๆ มาให้พิจารณาครับ
| คุณสมบัติ | FastAPI | Flask | Django REST Framework (DRF) |
|---|---|---|---|
| ประเภท Framework | Microframework + API-focused | Microframework | Full-stack (DRF คือ Extension ของ Django) |
| ความเร็ว (Performance) | สูงมาก (ASGI, async/await) | ปานกลาง (WSGI) | ปานกลาง (WSGI, มี Overhead จาก ORM และ Features อื่นๆ) |
| Type Hints & Validation | ยอดเยี่ยม (Pydantic, Built-in) | ต้องใช้ Libraries เสริม | มีในระดับหนึ่ง (Django Model, DRF Serializers) |
| เอกสาร API อัตโนมัติ | ยอดเยี่ยม (Swagger UI, ReDoc) | ต้องใช้ Libraries เสริม (เช่น Flask-RESTX) | มีในระดับหนึ่ง (DRF Spectactular, drf-yasg) |
| Asynchronous Support | Built-in (async/await) | รองรับในเวอร์ชันใหม่ (async view) แต่ยังไม่เต็มรูปแบบเท่า FastAPI | รองรับในเวอร์ชันใหม่ (async view) แต่ยังไม่เต็มรูปแบบเท่า FastAPI |
| Dependency Injection | Built-in และใช้งานง่าย | ต้องทำเอง หรือใช้ Libraries เสริม | ทำได้ แต่ไม่เป็น Native Feature |
| Learning Curve | ค่อนข้างต่ำสำหรับ API | ต่ำ | ปานกลางถึงสูง (ต้องเรียนรู้ Django ก่อน) |
| เหมาะสำหรับ | API-only microservices, high-performance web APIs | Simple web apps, small APIs | Complex web apps, full-stack APIs, apps ที่ต้องการ ORM และ Admin Panel |
จากตารางจะเห็นว่า FastAPI มีจุดเด่นชัดเจนในเรื่องของประสิทธิภาพ การตรวจสอบข้อมูล และการสร้างเอกสาร API อัตโนมัติ ทำให้เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการสร้าง REST API สมัยใหม่ครับ
ข้อควรพิจารณาในการนำ FastAPI ไปใช้งานจริง
แม้ว่า FastAPI จะมีข้อดีมากมาย แต่ในการนำไปใช้งานจริง คุณอาจต้องพิจารณาประเด็นเพิ่มเติมดังต่อไปนี้ครับ
Database Integration
ในตัวอย่างที่เราทำกันมา เราใช้ In-memory Dictionary ซึ่งไม่เหมาะกับการใช้งานจริงครับ สำหรับโปรเจกต์จริง คุณจะต้องเชื่อมต่อกับ Database (เช่น PostgreSQL, MySQL, MongoDB) และใช้ ORM (Object-Relational Mapper) หรือ ODM (Object-Document Mapper) เพื่อจัดการข้อมูลครับ
Frameworks ORM ยอดนิยมที่ใช้กับ FastAPI ได้แก่:
- SQLAlchemy: เป็น ORM ที่ทรงพลังและยืดหยุ่นมาก สามารถทำงานร่วมกับ FastAPI ได้ดีเยี่ยมครับ
- Tortoise ORM: เป็น ORM แบบ Async-first ที่ออกแบบมาเพื่อทำงานกับ Frameworks แบบ Async โดยเฉพาะครับ
- SQLModel: สร้างโดยผู้สร้าง FastAPI เอง ซึ่งรวมเอา Pydantic และ SQLAlchemy เข้าด้วยกันเพื่อประสบการณ์การพัฒนาที่ราบรื่นครับ
คุณสามารถศึกษาการใช้งาน ORM เหล่านี้เพิ่มเติมเพื่อเชื่อมต่อ FastAPI กับ Database ของคุณได้ครับ อ่านเพิ่มเติม
Authentication & Authorization
ในการใช้งานจริง คุณจะต้องมีระบบยืนยันตัวตน (Authentication) และระบบกำหนดสิทธิ์การเข้าถึง (Authorization) ที่ซับซ้อนกว่าแค่ API Key ง่ายๆ ครับ
- JWT (JSON Web Tokens): เป็นมาตรฐานยอดนิยมสำหรับการยืนยันตัวตนใน REST API
- OAuth2: เป็น Protocol สำหรับ Authorization ที่ใช้กันอย่างแพร่หลาย
FastAPI มี Tools และ Libraries สำหรับการนำ OAuth2 และ JWT มาใช้ได้อย่างง่ายดายผ่าน Dependency Injection ครับ
Deployment
หลังจากพัฒนา API เสร็จแล้ว คุณจะต้อง Deploy แอปพลิเคชัน FastAPI ของคุณไปยัง Server เพื่อให้พร้อมใช้งานจริงครับ
- Gunicorn + Uvicorn: Gunicorn เป็น Production-ready WSGI HTTP server ที่สามารถใช้เป็น Process Manager สำหรับ Uvicorn ได้ (รัน Uvicorn Worker หลายๆ ตัว)
- Docker: การสร้าง Docker Image สำหรับ FastAPI App ของคุณเป็นวิธีที่ยอดเยี่ยมในการทำให้การ Deploy ง่ายและสม่ำเสมอในสภาพแวดล้อมที่แตกต่างกันครับ
- Cloud Platforms: สามารถ Deploy ไปยัง Cloud Platforms ต่างๆ เช่น AWS (EC2, Lambda), Google Cloud (Cloud Run, App Engine), Azure (App Service) ได้ครับ
การเลือกวิธีการ Deploy ขึ้นอยู่กับความต้องการและงบประมาณของโปรเจกต์ครับ อ่านเพิ่มเติม
คำถามที่พบบ่อย (FAQ)
FastAPI เหมาะกับโปรเจกต์แบบไหน?
FastAPI เหมาะอย่างยิ่งสำหรับการสร้าง RESTful API, Microservices, หรือ Web APIs ที่ต้องการประสิทธิภาพสูง การพัฒนาที่รวดเร็ว และมีการตรวจสอบข้อมูลที่แข็งแกร่งครับ นอกจากนี้ยังเหมาะสำหรับโปรเจกต์ที่ต้องการ Asynchronous Operations เป็นหลักครับ
FastAPI เร็วกว่า Flask/Django จริงหรือ?
ใช่ครับ โดยทั่วไปแล้ว FastAPI จะเร็วกว่า Flask และ Django ในการจัดการ Requests ครับ เนื่องจากมันใช้ ASGI (Asynchronous Server Gateway Interface) และ Asynchronous Programming (async/await) ตั้งแต่แก่น ทำให้สามารถจัดการกับ I/O-bound operations ได้อย่างมีประสิทธิภาพมากกว่า Frameworks แบบ WSGI ดั้งเดิมครับ
ต้องรู้ Async/Await ไหมถึงจะใช้ FastAPI ได้?
ไม่จำเป็นต้องเป็นผู้เชี่ยวชาญครับ แต่การมีความเข้าใจพื้นฐานเกี่ยวกับ Asynchronous Programming และการใช้งาน async/await จะช่วยให้คุณสามารถใช้ประโยชน์จาก FastAPI ได้อย่างเต็มที่ครับ FastAPI สามารถทำงานกับฟังก์ชันปกติ (def) ได้เช่นกัน แต่ถ้าคุณต้องการประสิทธิภาพสูงสุดสำหรับ I/O-bound tasks การใช้ async def จะดีกว่าครับ
Pydantic คืออะไร และทำไมถึงสำคัญกับ FastAPI?
Pydantic คือ Library สำหรับ Data Validation และ Settings Management ใน Python โดยอาศัย Python Type Hints ครับ Pydantic มีความสำคัญกับ FastAPI อย่างมากเพราะมันช่วยให้ FastAPI สามารถ:
- ตรวจสอบข้อมูล (Validate) ใน Request Body, Path, Query Parameters ได้โดยอัตโนมัติ
- แปลงข้อมูล (Parse) จาก Request Body (เช่น JSON) เป็น Python Objects ได้ง่ายดาย
- สร้างเอกสาร API (Swagger UI / ReDoc) ได้อย่างแม่นยำจาก Pydantic Models ที่คุณกำหนด
จะ Deploy FastAPI อย่างไร?
มีหลายวิธีครับ วิธีที่นิยมที่สุดคือการใช้ Uvicorn ใน Production ร่วมกับ Gunicorn เพื่อจัดการ Worker Processes ครับ นอกจากนี้ยังสามารถใช้ Docker เพื่อสร้าง Containerized Application และ Deploy ไปยัง Cloud Platforms ต่างๆ ได้อีกด้วยครับ
มีข้อจำกัดอะไรบ้างในการใช้ FastAPI?
แม้จะมีข้อดีมากมาย แต่ FastAPI ก็มีข้อควรพิจารณาบ้างครับ:
- ไม่มี ORM หรือ Database Integration ในตัว: คุณต้องเลือกและติดตั้ง ORM/ODM ด้วยตัวเอง (ซึ่งบางคนก็ชอบเพราะมีความยืดหยุ่น)
- ไม่ใช่ Full-stack Framework: หากคุณต้องการสร้าง Web Application ที่มีทั้ง Backend และ Frontend ใน Framework เดียว (เช่น Django) FastAPI อาจต้องใช้ร่วมกับ Frontend Framework อื่นๆ (เช่น React, Vue, Angular) ครับ
- Learning Curve สำหรับ Async: สำหรับนักพัฒนาที่ไม่คุ้นเคยกับ Asynchronous Programming อาจจะต้องใช้เวลาเรียนรู้เพิ่มเติมครับ
สรุปและ Call-to-Action
ตลอดบทความนี้ เราได้สำรวจโลกของ FastAPI ตั้งแต่การติดตั้งพื้นฐาน การสร้าง API แรก การจัดการ Path และ Query Parameters ไปจนถึงการใช้ Pydantic เพื่อจัดการ Request Body, การทำ Validation, Error Handling และ Dependency Injection ครับ นอกจากนี้เรายังได้เห็นถึงพลังของการสร้างเอกสาร API อัตโนมัติและการเปรียบเทียบกับ Frameworks อื่นๆ ซึ่งทั้งหมดนี้ยืนยันว่า FastAPI เป็นเครื่องมือที่ทรงพลัง มีประสิทธิภาพ และตอบโจทย์การสร้าง REST API ในยุคปัจจุบันได้อย่างยอดเยี่ยมจริงๆ ครับ
ไม่ว่าคุณจะเป็นนักพัฒนา Python มือใหม่ที่กำลังมองหา Framework สำหรับสร้าง API ตัวแรก หรือนักพัฒนามากประสบการณ์ที่ต้องการยกระดับประสิทธิภาพและความเร็วในการพัฒนา FastAPI คือตัวเลือกที่ไม่ควรมองข้ามครับ ด้วยความสามารถในการใช้ Python Type Hints อย่างเต็มรูปแบบ, ประสิทธิภาพที่เหนือกว่าด้วย ASGI และ Asynchronous Programming, รวมถึงการสร้างเอกสาร API อัตโนมัติ ทำให้คุณสามารถสร้าง APIs คุณภาพสูงได้อย่างรวดเร็วและมั่นใจครับ
ถึงเวลาแล้วครับที่คุณจะนำความรู้ที่ได้จากบทความนี้ไปลงมือปฏิบัติจริง ลองสร้าง API ของคุณเองด้วย FastAPI ดูนะครับ หากคุณพบปัญหาหรือต้องการเรียนรู้เพิ่มเติม SiamLancard.com ยินดีเป็นส่วนหนึ่งในการสนับสนุนการเรียนรู้ของคุณเสมอครับ อย่าลังเลที่จะทดลองและสร้างสรรค์สิ่งใหม่ๆ ครับ!
หากคุณสนใจเรียนรู้เรื่องการพัฒนา Web หรือ API ในภาษาโปรแกรมมิ่งอื่นๆ หรือต้องการเจาะลึกในหัวข้อเฉพาะของ Python และ FastAPI อ่านเพิ่มเติม ได้เลยครับ เรามีบทความและแหล่งความรู้อีกมากมายรอคุณอยู่ครับ!