FastAPI ทำ To Do app

ทดลองการใช้ FastAPI ทำแอพ To do list แบบง่ายๆโดยใช้ swagger UI และ hypercorn

FastAPI ทำ To Do app

สวัสดี FastAPI

กระแสในช่วงนี้เวลาทำโปรเจคส่วนใหญ่ก็จะแยกเป็น หน้าบ้าน (Front-end) กับหลังบ้าน (Back-end) อย่างชัดเจนซึ่ง ในส่วนนี้เอง Python ก็มีมารองรับเช่นกันค่อนข้างหลากหลาย อาทิเช่น Django REST framework, Falcon, Flask ซึ่งเรื่อง ประสิทธิภาพ ก็มี ความแรงพอตัวอยู่แล้ว แต่วันนี้ทาง STACKPYTHON จะมาแนะนำ ตัวจี๊ด จากทาง Python นั่นก็คือเจ้า FastAPI นั้นเอง

https://fastapi.tiangolo.com

และนี้คือ 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 FastAPIapp = 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

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, modelsfrom tortoise.contrib.pydantic import pydantic_model_creatorclass 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.titleTodos_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_tortoisefrom models.todo import Todos, Todos_Pydantic, TodosIn_Pydanticapp = 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](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

- จากนั้นให้เราดูผลลัพธ์ที่ FastAPI ทำการ Response (ตอบกลับ)

จะเห็นได้ว่าเราได้ทำการ แก้ไข จาก   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](https://github.com/cckcoder/fastapi_todo) ได้เลยครับ ถ้าหากเพื่อนต้องการ Feedback
หรือมีข้อเสนอแนะก็ แนะนำกันเข้ามาได้ครับ

Github:  [https://github.com/cckcoder/fastapi_todo](https://github.com/cckcoder/fastapi_todo)

Pydantic:
[https://pydantic-docs.helpmanual.io](https://pydantic-docs.helpmanual.io)

hypercorn: [https://pgjones.gitlab.io/hypercorn/](https://pgjones.gitlab.io/hypercorn/)