สัญญา(ไม่)ปากเปล่า - data contracts in action (Python)
blog ที่แล้ว เราคุยกันถึง data contract กับ NodeJS รอบนี้ เรามาใช้ Python กันบ้างฮะ
สำหรับ NodeJS กดที่ลิงก์ข้างล่างได้เลย
ย้อนความนิดนึง
ใน ETL มันมี extract ถูกมั้ยฮะ ซึ่งในขั้น extract ก็ควร validate ค่าที่เข้ามาด้วย ตรง validate นี่แหละ ที่เราสนใจ เพื่อให้ข้อมูลมีคุณภาพเพียงพอที่เราจะเอาไปใส่ใน database ได้
และเราก็จะสร้าง API มารับข้อมูลและ validate โดยใช้ OpenAPI กับ Python library ตัวนึงที่เอาไว้ทำ validation นั่นคือ jsonschema
ฮะ
API Swagger
ขอ recycle ของเก่า API definition file people
ฮะ
อ้อ pets
ด้วย
เขียน app พร้อม validation
เรามารู้จัก jsonschema
กัน เจ้า library ตัวนี้ใช้ validate object โดยอ้างอิงกับ schema ที่เราต้องการ คือหลักการเหมือนกับ AJV ใน NodeJS เลยฮะ
1. สร้าง python app
เริ่มจาก sample Flask app
แล้วติดตั้ง requirements
แค่นี้ เราก็จะได้ API app มาแล้วฮะ
2. อ่าน contract
เราจะเริ่มจากหนึ่ง contract ก็คือ people
ก่อนนะฮะ
ตรงบรรทัดที่ 6-7 นั่นคือเราไปอ่าน contract file เก็บไว้ในตัวแปรcontract
3. Validate
- บรรทัด 9: รับ payload ด้วย
request.get_json()
- บรรทัด 10: อ้างอิงค่า schema ของ contract จาก
/components/schemas/people
- บรรทัด 11: validate payload และ contract ด้วย
jsonschema.validate()
- บรรทัด 12: return
200
คือ "OK" ถ้า validate ถูกต้อง แต่ถ้าไม่ เราจะได้ "500 Internal Server Error" แทน แบบข้างล่างนี้ฮะ
4. Handling errors
ตรง error ตะกี้ มันไม่สื่อเท่าไหร่ เรามาลองปรับให้มันดูดีขึ้นกัน
- ถ้า validate ถูกต้อง ให้ return
200
ในtry
block - ถ้าเกิด validation error ให้ return
400
พร้อม message จากjsonschema.ValidationError.message
ในexcept
block อันแรก - แต่ถ้า error อย่างอื่น ก็ return
400
เหมือนกันแต่ print log แทน
5. Complete API
6. Test
กรณี payload ถูกต้อง
กรณี payload มีบาง field ระบุ type ไม่ถูกต้อง
กรณี payload ไม่มี required field
ถ้ามีหลาย contract ?
ตอนนี้เราสามารถ validate people
contract ได้แล้ว ละถ้าเรามี pets
และต้องการ validate ทั้งคู่พร้อมกันล่ะ
เราควรจะต้องมี generic function ประมาณนี้ฮะ
- บรรทัด 8-13: อ่าน contract files เก็บไว้ใน
dict
ให้ key เป็นชื่อ file - บรรทัด 16-30: refactor ตรงส่วน validation ให้อยู่ใน generic function โดยรับค่า parameter เป็น contract key (อ้างอิงใน
dict
) และ payload
เวลาเรียก ก็เรียกจาก endpoint แต่ละอันฮะ
นี่คือ code ตัวเต็ม
ลองเรียก API ด้วย payload ที่ไม่ถูกต้อง จะได้ผลลัพท์แนวๆ นี้
เอาล่ะ แค่นี้ก็ได้ API ง่ายๆ พร้อม contract validation ด้วย python แล้วฮะ
Repo
สามารถดู source code ทั้งหมดใน repo ด้านล่างนี้ฮะ