สวัสดี FastAPI
กระแสในช่วงนี้เวลาทำโปรเจคส่วนใหญ่ก็จะแยกเป็น หน้าบ้าน (Front-end) กับหลังบ้าน (Back-end) อย่างชัดเจนซึ่ง ในส่วนนี้เอง Python ก็มีมารองรับเช่นกันค่อนข้างหลากหลาย อาทิเช่น Django REST framework, Falcon, Flask ซึ่งเรื่อง ประสิทธิภาพ ก็มี ความแรงพอตัวอยู่แล้ว แต่วันนี้ทาง STACKPYTHON จะมาแนะนำ ตัวจี๊ด จากทาง Python นั่นก็คือเจ้า FastAPI นั้นเอง
และนี้คือ Official ของทาง FastAPI เอาละครับเพื่อไม่ให้เป็นการเสียเวลา ไปลุยกันเลยครับ ในขั้นตอนแรก เราก็ทำการ Create project folder ในเคสนี้ผมขอตั้งชื่อว่า fastapi_todo นะครับ จากนั้นเราก็ทำการสร้าง virtual environment โดยใช้คำสั่ง
python3 -m -venv env
และทำการ Activate virtual env ด้วยคำสั่ง
source env/bin/activate #for linux
env/Scripts/activate #for windows
ต่อมาเราก็ทำการติดตั้ง fastapi
pip install fastapi
และตามด้วย hypercorn
pip install hypercorn
*สร้างไฟล์ main.py
ทำการ implement code ดังนี้
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def hello_world():
return {'hello': 'world'}
@app.get("items/me")
def read_item_me():
return {'item_id': 'current item'}
@app.get("/items/{item_id}")
def get_items_by_id(item_id: int):
return {'item_id': f'Hello item no {item_id}'}
เสร็จแล้วเรามาทดลองรัน เจ้า FastAPI กันเลยครับโดยการเปิด Terminal และรันคำสั่ง
hypercorn main:app -reload
เพื่อให้แน่ใจว่า
รันได้อย่างถูกต้อง ให้ทำการเข้าไปที่ http://localhost:8000/docs
ถ้าเกิด Browser แสดงผลลัทธ์แบบข้างบน แสดงว่า FastAPI รันได้ถูกต้อง
ในส่วนของหน้าการแสดงผลแบบนี้เราเรียกว่า Swagger UI ซึ่งสามารถเอาไว้จัดการกับ FastAPI ได้เลยเหมือนกับเพื่อนๆ มี Post Man แบบ Build-in มาให้ครับเอาละเรามาลองเล่นเจ้า Swagger UI กันเล็กๆน้อยๆครับ เราสามารถทดสอบได้โดยการคลิกที่แถบ GET จากนั้นจะให้เลือก Try it out ในเคสที่ผมเลือกนั้นเพื่อนๆสามารถ input parameter ได้เลยจากนั้นให้กด Execute เจ้า Swagger UI ก็จะยิง Request ไปที่ FastAPI และทำการ Response ผลลัพธ์ กลับมา พร้อมกับบอก Response code มาด้วย
เอาละอันนี้เป็นพื้นฐานทั่วไปของ FastAPI ต่อมาเรามาลองทำ
Workshop To do app โดยประยุกต์ใช้ FastAPI กันครับก่อนอื่นใน
Workshop นี้มีการเชื่อมต่อกับ Database ด้วยโดยใช้ ไลบรารี่ Tortoise ORM
https://tortoise-orm.readthedocs.io
ใน workshop todo เราก็จะทำ CRUD (Create, Read, Update and Delete)
from tortoise import fields, models
from tortoise.contrib.pydantic import pydantic_model_creator
class Todos(models.Model):
id = fields.IntField(pk=True)
title = fields.CharField(max_length=255)
is_complete = fields.BooleanField(default=False)
create_at = fields.DatetimeField(auto_now_add=True)
modified_at = fields.DatetimeField(auto_now=True)
def __str__(self) -> str:
return self.title
Todos_Pydantic = pydantic_model_creator(Todos, name="Todo")
TodosIn_Pydantic = pydantic_model_creator(
Todos, name="TodoIn", exclude_readonly=True
)
จากนั้นให้ทำการสร้าง
class Todos และทำการสืบทอดคุณสมบัติ models จาก tortoise-orm
และทำการ Todos import pydantic ซึ่งเจ้า pydantic ก็คือการประกาศ type หรือชนิดให้กับตัวแปรนั้นเอง
ในส่วนของ class Todos จากประกอบไปด้วย Field id , title , is_complete , create_at , modified_at จากนั้นในส่วนของการ เพิ่มลบแก้ไขจะอยู่ในส่วน Todos_Pydantic กับ TodosIn_Pydantic นั้นเอง
Todos_Pydantic นั้นจะให้ทำการอ่านข้อมูลจาก ฐานข้อมูลได้เท่านั้น ส่วน TodosIn_Pydantic จะสามารถเพิ่ม และ แก้ไข ได้
จากนั้นมาที่ main.py เราก็ทำการสร้าง Route GET , POST , PUT , DELETE สำหรับ CRUD
โดยทำการ
Implement โค้ดตามนี้
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from models.todo import Todos, Todos_Pydantic, TodosIn_Pydantic
app = FastAPI()
@app.get("/")
def route():
return {'msg': 'well come FastAPI todo list'}
@app.get('/todos')
async def show_all_todos():
return await Todos_Pydantic.from_queryset(Todos.all())
@app.get('/todo/{todo_id}')
async def todo_by_id(todo_id: int):
return await Todos_Pydantic.from_queryset_single(Todos.get(id=todo_id))
@app.post('/todo')
async def create_todo(todo: TodosIn_Pydantic):
todo_obj = await Todos.create(**todo.dict(exclude_unset=True))
return await TodosIn_Pydantic.from_tortoise_orm(todo_obj)
@app.put('/todo/{todo_id}')
async def update_todo(todo_id:int, todo: TodosIn_Pydantic):
await Todos.filter(id=todo_id).update(**todo.dict(exclude_unset=True))
return await Todos_Pydantic.from_queryset_single(Todos.get(id=todo_id))
@app.delete('/todo/{todo_id}')
async def delete_todo(todo_id: int):
todo_count = await Todos.filter(id=todo_id).delete()
if not todo_count:
return {'msg': f"Todo {todo_id} not found!"}
return {'msg': f"Todo {todo_id} delete successfull!"}
register_tortoise(
app,
db_url='sqlite://db.sqlite2',
modules={'models': ['main']},
generate_schemas=True,
add_exception_handlers=True
)
ขั้นตอนแรกเราทำการ import fastapi, tortoise-orm และ ในส่วนของ models todo.py
ซึ่ง ในการเรียกใช้งาน function นั้นเราต้อง ใช้เป็น async และ await เนืองจาก tortoise-orm รองรับการทำงานแบบ async, await จะเห็นได้ว่าในส่วนที่มีการแสดง ข้อมูล อย่างเช่น Route /todos นั้นเราเรียกใช้งาน
Todos_Pydantic เนื่องจากเป็นการแสดงผล (READ) แต่ถ้าหากเป็นในส่วนของ @app.put('/todo/{todo_id}') นั้น เราจะใช้เป็น TodosIn_Pydantic เราประกาศแบบนี้เพื่อให้มีการทำงานในส่วนต่างๆ ที่เฉพาะเจาะจงไปเลย ต่อมาเราต้องทำการ Register เจ้า app ของเราในการเชื่อมต่อฐานข้อมูล
เรามาดูกันในส่วนของ ฟังก์ชั่น register_tortoise นั้นคือการ Register app กับ ฐานข้อมูลนั้นเอง ในworkshop นี้ผมขอใช้เป็น sqlite เอาละเรามาลองดูผลลัพธ์กันเลยครับ ให้ทำการ Start FastAPI ด้วยคำสั่งhypercorn main:app --reload
หลังจากที่เรารัน FastAPI แล้ว sqlite ก็จะถูกสร้างข้้นมาด้วย เอาละเราก็เข้าไปที่ http://localhost:8000/docs เพื่อดูการแสดงผลของ workshop todo และเพื่อให้ทราบว่า FastAPI ของเราไม่ติด Error อะไร
ถ้าหากปรากฏหน้าแสดงผลแบบนี้ แสดงว่าไม่ติดอะไร นะครับ
จากนั้นเราก็ทำการทดสอบ
ด้วยการ เพิ่มรายการ todo เข้าไปครับ โดยเข้าไปที่ POST /todo
เลือก Try it out และทำการกรอกข้อมูลลงไปครับ หลังจาก เพิ่มเสร็จแล้วให้ทำการกดปุ่ม Execute เพื่อดูผลลัพธ์ครับ
เลื่อนลงมาในส่วนของ Responses แสดงผล สถานะ 200 คือผ่านนั้นเอง
เพื่อความแน่ใจให้เราไปดู รายการ todo จาก Route GET /todos ครับ จะเห็นได้ว่าข้อมูลที่เราได้เพิ่มเข้าไปก็ถูกบันทึกลง ฐานข้อมูลเรียบร้อยครับ จากนั้นให้ทำการเพิ่มรายการ todo เข้าไปอีกสัก 2 รายการครับ
จากนั้นให้เราทดสอบการ อัพเดทข้อมูลกันครับ ไปที่ Route PUT /todo/{todo_id}
ผมจะทำการอัพเดท todo “Do homework” ซึ่งมี todo_id
เท่ากับ 1
จะเห็นได้ว่าเราได้ทำการ แก้ไข จาก is_complete:False เป็น True เรียบร้อย จากนั้นเพื่อความแน่ใจให้เราไปเช็คในส่วนของ GET /todos อีกทีนึง
เราจะเห็นได้ว่า Do home ได้ถูกอัพเดท is_complete เป็น True เรียบร้อย
ต่อมาเรามาดูในส่วนของการลบกันบ้างนะครับ ให้เราไปที่ Route DELETE /todo/{todo_id}
ในส่วนนี้ค่อนข้างตรงไปตรงมาครับให้เราใส่ todo_id ที่เราต้องการลบได้เลย
ในเคสนี้ผมจะใส่ todo_id 1 นะครับ
หลังจากกด Execute แล้ว ในส่วนของผลลัพธ์ คือข้อมูลได้ถูกลบแล้วนั้นเองครับ
จากนั้นเราก็กลับไปตรวจสอบดูอีกครั้งนึงครับว่า todo_id ได้ถูกลบไปแล้วจริงๆ
ก็มาในส่วนของ
Route GET /todos ครับ
ผลลัพธ์ที่ได้คือ id หมายเลข 1 ได้ถูกลบไปเรียบร้อยแล้วครับ
เอาละครับเราก็จบ workshop FastAPI To do list กันเป็นที่เรียบร้อยแล้วไม่อยากละไม่ง่ายเกินไปนะครับ ขอขอบคุณผู้อ่านทุกๆท่านครับ หวังว่าบทความนี้เป็นประโยชน์ให้กับเพื่อนๆ ไม่มากก็น้อย
ในส่วนของ โค้ดนั้น เพื่อนๆเข้าดูได้ที่ Github ได้เลยครับ ถ้าหากเพื่อนต้องการ Feedback หรือมีข้อเสนอแนะก็ แนะนำกันเข้ามาได้ครับ
Github: https://github.com/cckcoder/fastapi_todo
Pydantic:
https://pydantic-docs.helpmanual.io
hypercorn: https://pgjones.gitlab.io/hypercorn/
กิจกรรมที่กำลังจะมาถึง
ไม่พลาดกิจกรรมเด็ด ๆ ที่น่าสนใจ
Event นี้จะเริ่มขึ้นใน April 25, 2023
รายละเอียดเพิ่มเติม/สมัครเข้าร่วมคอร์สเรียนไพธอนออนไลน์ที่เราได้รวบรวมและได้ย่อยจากประสบการณ์จริงและเพื่อย่นระยะเวลาในการเรียนรู้ ลองผิด ลองถูกด้วยตัวเองมาให้แล้ว เพราะเวลามีค่าเป็นอย่างยิ่ง พร้อมด้วยการซัพพอร์ตอย่างดี