ขอบคุณโลโก้จาก (FastAPI)

FastAPI คือ framework ที่ใช้สำหรับการทำ API ด้วยภาษา Python ซึ่งเป็นภาษาที่หลาย ๆ คนน่าจะคุ้นเคยดี โดยจุดเด่นของเจ้า FastAPI คือ ความรวดเร็วในการทำงาน ง่ายต่อการเรียนรู้ และมี API document อยู่ในตัวที่จะช่วยให้เราทดสอบไปพร้อมกับการพัฒนาได้อย่างทันที อย่ารอช้า มาเริ่มต้นทำไปพร้อมกันได้เลย

**หมายเหตุ ในบทความนี้จะมีการใช้งานโปรแกรมเขียนโค้ดผ่าน Vistual Studio Code และมีการพูดถึง HTTP methods ต่าง ๆ หากผู้อ่านยังไม่คุ้นเคย สามารถอ่านได้ที่ HTTP request methods

ขั้นตอนแรก setup และ install

สร้าง folder สำหรับเก็บไฟล์ของโปรเจคของเรา และเช้าไปใน folder โดยก่อนอื่นต้องมี python เวอร์ชัน 3.6 ขึ้นไป (ถ้ายังไม่มี โหลดได้ที่ Download Python) และแนะนำให้สร้าง virtual environment เพื่อให้สะดวกต่อการจัดการ library ต่าง ๆ โดยไม่กระทบกับโปรเจคอื่น

การสร้าง virtual environment สามารถทำได้โดยการ run คำสั่งผ่าน command line และเพื่อความสะดวก ผู้เขียนแนะนำให้ใช้ผ่าน terminal ของโปรแกรมการเขียนโค้ดของ Visual Studio Code ได้เลย

Vistual Studio Code

คำสั่งสำหรับสร้าง virtual environment

FastAPI project> python3 -m venv env

แล้วทำการ activate เพื่อเข้าใช้งาน virtual environment ที่เพิ่งสร้าง ด้วยคำสั่ง

FastAPI project> .\env\Scripts\activate

เมื่อเข้ามาได้แล้ว จะมีชื่อ virtual environment ที่เราตั้งไว้ขึ้นอยู่ข้างหน้า จากนั้นเราก็จะทำการติดตั้ง library ที่เกี่ยวข้อง คือ FastAPI ของเรา และ Uvicorn ซึ่งเป็นตัวช่วยในการ run server ให้เราใช้งานเจ้า FastAPI โดยทั้งสองอย่างนี้สามารถติดตั้งโดยใช้คำสั่งตามนี้ได้เลย

(env) FastAPI> pip install fastapi
(env) FastAPI> pip install uvicorn

เริ่มต้นสร้าง API

ขั้นตอนแรกสร้างไฟล์ชื่อ main.py ขึ้นมาและลองคัดลอกโค้ดข้างล่างนี้ไปใส่ดู จะเป็นการเริ่มต้นสร้าง route แรกขึ้นมาโดย route นี้จะตอบกลับค่าในรูปแบบ JSON ว่า {“message”: “Hello World”}

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"message": "Hello World"} 

จากนั้นให้ทำการ run server ขึ้นมาโดยการพิมพ์คำสั่งข้างล่างนี้ผ่าน terminal โดยการใส่ –reload ต่อข้างหลัง ซึ่งจะช่วยให้เวลาเราแก้ไขโค้ด server จะ auto-reload โค้ดใหม่นี้เข้าไปให้โดยอัตโนมัติเลย

uvicorn main:app --reload
ผลลัพธ์เมื่อ run server สำเร็จ

ทำการเปิด http://127.0.0.1:8000 บน web browser ดู จะเห็น response ที่ส่งกลับมาจาก route แรกที่เราสร้างขึ้น

ผลลัพธ์เมื่อเปิด http://127.0.0.1:8000

ที่นี้เรามาลองเปิด API document โดยเข้าไปที่ http://127.0.0.1:8000/docs ที่เป็นของ Swagger UI ซึ่งจะแสดง API route ที่เราสร้างขึ้นมา

Swagger UI

ในหน้านี้เราสามารถยิงทดสอบ API จริงดูได้เลย ทำให้ไม่ต้องเสียเวลาสร้าง request ขึ้นมาเอง การทดสอบให้เลือก route ที่ต้องการทดสอบ จากนั้นกดปุ่ม Try it out และปุ่ม Execute เพื่อทำการส่ง request ไป จะเห็น response กลับมาเป็นผลลัพธ์ข้อความว่า Hello World ของเรา

หลังกดเลือก route ให้กดปุ่ม Try it out
กดปุ่ม Execute เพื่อส่ง request แล้วจะมี response กลับมาตามการทำงานของ route

ลองสร้าง route ที่มีการรับ parameter

โดยเราลองมาเริ่มที่ method GET ที่มีการรับ path parameter สำหรับตัวอย่างนี้ เราจะกำหนด route เป็น “/user/{user_id}” มีตัวแปรที่รับมาคือ user_id ซึ่งเราสามารถกำหนดประเภทของตัวแปรได้ ในที่นี้เราจะกำหนดให้เป็น interger โดยภายในฟังก์ชันเราจะไม่มีการทำอะไร แต่จะส่งค่า user_id ที่ได้รับมาคืนกลับไปเพื่อแสดงผลเลย route นี้สามารถเขียนได้ตามโค้ดข้างล่างนี้

@app.get("/user/{user_id}")
async def get_user_by_id(user_id: int):
    return {"user_id": user_id} 


เมื่ออัพเดตโค้ดเรียบร้อย server จะทำการ restart ให้อัตโนมัติ เมื่อเราทำการ refresh หน้า Swagger ก็จะเห็น route ใหม่ที่เราสร้างขึ้นมา และมีช่องตัวแปร user_id ไว้ให้เราทดลองกรอกค่าตัวแปรได้เลย จะเห็นว่ามีการตรวจสอบค่าที่เราใส่เข้าไป เช่น ในตัวอย่างข้างล่าง หากเรากรอก “one” เข้าไปและกดปุ่ม Execute จะมีการแจ้งเตือนว่าใส่ค่าไม่ตรงประเภทของตัวแปรที่กำหนด

แจ้งเตือนเมื่อใส่ค่าตัวแปรผิดประเภท

หากกรอกค่าถูกต้อง และกดปุ่ม execute ผลลัพธ์ที่เป็น user_id ก็จะออกมาตามโค้ดที่เราเขียนไปข้างต้น ดังรูปข้างล่าง

เมื่อใส่ค่าถูกประเภท จะได้ response ออกมา

ทีนี้ลองเพิ่ม query parameter กันดูบ้าง โดยสามารถใส่ตัวแปรเพิ่มเข้าไปในฟังก์ชัน get_user_by_id ต่อกับ user_id ได้เลย ในตัวอย่างนี้ เราจะทำการเพิ่มตัวแปรชื่อ type ประเภทตัวแปรเป็น string และกำหนดให้สามารถเลือกได้ว่าจะใส่ค่ามาหรือไม่ใส่ค่ามาก็ได้ โดยการเพิ่ม Optional เข้าไป หากอยากกำหนดค่า default เมื่อไม่ได้มีการใส่ค่ามา ก็สามารถใส่ = “default” ได้เลย ในตัวอย่างจะกำหนดค่า default เป็น “normal” โค้ดที่แก้ไขเพิ่มเติมจะเป็นดังนี้

from typing import Optional 

@app.get("/user/{user_id}")
async def get_user_by_id(user_id: int, type: Optional[str] = "normal"):
    return {"user_id": user_id, "type": type} 

กลับมา refresh หน้า swagger ของเรา ลองทดสอบไม่ใส่ค่าตัวแปร type เมื่อกดปุ่ม execute จะได้ค่า default ที่ตั้งไว้คือ “normal” คืนกลับมาแทน ดังตัวอย่างข้างล่าง

ผลลัพธ์เมื่อกำหนด field type เป็น optional และ default value เป็น “normal”

ผลลัพธ์เมื่อทดลองกำหนดค่า field type เป็น special
จะเห็นว่าใน request url มีการส่งค่า query parameter ของ type เพิ่มขึ้นมา

กำหนด request body ด้วย pydantic

ขั้นตอนต่อไป เราจะมาลองทำ method POST เพื่อใช้สำหรับสร้าง item ขึ้นมา โดยรายละเอียดของ item ที่ผู้ใช้ต้องการสร้างขึ้นนี้ เราจะกำหนดให้ส่งมาใน request body ในรูปแบบของ JSON ซึ่งเราจะใช้ library pydantic มาช่วยในการจัดการและช่วยตรวจสอบความถูกต้องของโครงสร้างของข้อมูลที่ถูกส่งเข้ามา

เริ่มต้นจากการ import BaseModel class ของ pydantic ซึ่งสามารถเขียน import ได้ตามนี้

from pydantic import BaseModel 

จากนั้นเราจะเขียน class Item ที่สืบทอด BaseModel มา โดยเราจะกำหนด field และ type ของข้อมูลที่เราต้องการในนี้

class Item(BaseModel):
    id: int
    name: str
    item_type: Optional[str] = "a"
    total: int 

จากนั้นสร้าง route ชื่อ “/item” และกำหนดประเภทของตัวแปรโดยใช้ class Item ที่เราเพิ่งสร้างขึ้นมา

@app.post("/item")
def create_item(item: Item):
    return item 

เมื่อเปิด swagger ดูก็จะเห็น route /item ที่เป็น post method โดยมี request body เป็นรูปแบบเดียวกันกับ class Item

POST /item กับ request body ตามโครงสร้างของ Item

หากเราทดลองใส่ request body โดยมี fields ไม่ครบตามที่ต้องการ ระบบก็จะส่งข้อความ error กลับ เช่น ตัวอย่างในรูปข้างล่างไม่ได้ทำการส่ง field total ไปใน request body ด้วย ระบบก็ตอบกลับมาว่ามี field total ที่หายไป

ไม่ได้กำหนดค่า total ใน request body
response error กลับมาว่า field total ไม่มีค่า

บทสรุปทิ้งท้าย

จากตัวอย่างการใช้งานข้างต้น จะเห็นได้ว่า เราสามารถเริ่มต้นทำ API ได้ง่าย ๆ ด้วย Framework FastAPI ที่เขียนด้วยภาษา python ที่ช่วยให้สามารถพัฒนา API และเรียนรู้ได้อย่างรวดเร็ว ต่อจากนี้ ผู้เขียนก็หวังว่าผู้อ่านทุกท่านจะสามารถลองทำ method อื่น ๆ ได้เช่นกัน เช่น put หรือ delete โดยเข้าใจการรับค่ามาในรูปแบบ path parameter, request parameter หรือ request body ทั้งยังสามารถกำหนดชนิดของตัวแปร กำหนดว่าต้องใส่ค่ามาหรือไม่ และสำหรับ request body ก็สามารถใช้เจ้า pydantic ช่วยอำนวยความสะดวกในการจัดการและเช็คค่าที่รับเข้ามาได้

นอกจากนี้ FastAPI ยังสามารถทำอย่างอื่นได้อีกมากมาย ไม่ว่าจะเป็น การกำหนด response model ที่ให้เราสามารถกำหนดโครงสร้าง response ได้เหมือนที่เราทำกับ request body, การทำ Dependency Injection ที่จะช่วยเพิ่มความสะดวกในการใช้งาน เช่น การติดต่อกับ database หรือการกำหนด role permission ของแต่ละ route, และการทำ Middleware เมื่อเราต้องการจัดการอะไรบางอย่างให้ทุก request ที่เข้ามาหรือก่อนที่จะ response กลับไป ต้องผ่านฟังก์ชันที่เรากำหนดไว้เสียก่อน หวังว่าบทความนี้จะเป็นประโยชน์กับผู้อ่านที่อยากเริ่มต้นทำ API กันนะครับ

References

Data Engineer
Government Big Data institute (GBDi)

Data Scientist
Government Big Data institute (GBDi)

Recommended Posts