สถาปัตยกรรม
สถาปัตยกรรมGraphQL เซิร์ฟเวอร์แบบ Code-first

GraphQL เซิร์ฟเวอร์แบบ Code-first

GraphQL schema กำหนดสัญญาสำหรับ GraphQL service โดยเปิดเผยชุดของ types, fields และ mutations ที่สามารถใช้งานกับ service ได้ เมื่อสร้าง GraphQL service เราอาจเลือกได้ว่าจะ:

  • ให้ schema เป็นแหล่งข้อมูลที่เชื่อถือได้ และให้โค้ดการใช้งานทั้งหมดสอดคล้องกับนิยามของ schema
  • ให้โค้ดเป็นแหล่งข้อมูลที่เชื่อถือได้ และให้ schema เป็น artifact ที่ถูกสร้างขึ้นจากโค้ด

ในทั้งสองกรณี เราจะได้ GraphQL service ที่ทำงานได้อย่างสมบูรณ์ แต่ขึ้นอยู่กับแนวทางที่เลือกใช้ เราอาจทำฟีเจอร์ได้มากหรือน้อย ง่ายหรือยาก ในอนาคต แนวทางทั้งสองนี้เรียกตามลำดับว่า "schema-first" (หรือที่ถูกต้องกว่าคือ "SDL-first") และ "code-first"

Gato GraphQL ใช้แนวทาง code-first มาดูกันว่าเหตุใดจึงเป็นเช่นนั้น

เหตุใด Gato GraphQL จึงใช้ code-first

ในแนวทาง code-first เราเริ่มต้นด้วยการเขียน resolvers ก่อน จากนั้นโดยใช้โค้ดเป็นแหล่งข้อมูลเดียว เราจะมี schema ถูกสร้างขึ้นเป็น artifact ดังนั้น schema จึงถูกสร้างโดยการรันสคริปต์ แทนที่จะถูกสร้างด้วยมือเหมือนใน SDL-first เนื่องจาก code-first ก็มี schema เช่นกัน จึงไม่ขาดสิ่งสำคัญที่ SDL-first มีให้

อย่างไรก็ตาม code-first มีฟีเจอร์สำคัญเพิ่มเติมที่เหนือกว่า SDL-first: ความสามารถในการสร้าง dynamic schemas ซึ่งสามารถเปลี่ยนรูปร่างและ attributes ได้ตามบริบท และถูกควบคุมผ่านโค้ดในรันไทม์ แท้จริงแล้ว ฟีเจอร์ที่ยอดเยี่ยมทั้งหมดที่ Gato GraphQL มอบให้ล้วนเป็นผลโดยตรงจากการนำ code-first มาใช้

ข้อดีของ code-first

Dynamic schema มอบประโยชน์ทั้งหมดที่ระบุไว้ด้านล่างนี้ รวมถึงประโยชน์อื่นๆ อีกมากมาย:

แหล่งข้อมูลที่เชื่อถือได้สำหรับ schema เป็น superset ของสิ่งที่ GraphQL ต้องการ properties เพิ่มเติม (เช่น global fields, global connections, global directives และ persisted fragments) สามารถใช้ใน API ของเราได้แล้วโดยไม่ต้องรอให้มีการเพิ่มเข้าไปใน GraphQL spec ไม่ว่าจะมีการเพิ่มหรือไม่ก็ตาม

เนื่องจากแหล่งข้อมูลที่เชื่อถือได้ไม่ได้ผูกติดกับ schema เราจึงสามารถสร้าง schema สำหรับระบบอื่นๆ ได้เช่นกัน: GraphQL เป็นเพียงหนึ่งในเป้าหมาย ตัวอย่างเช่น สามารถสร้าง JSON-schema สำหรับ REST service จากแหล่งข้อมูลเดียวกันได้

API สามารถเป็นทั้ง public/private ในเวลาเดียวกันได้ ขึ้นอยู่กับว่าผู้ใช้เข้าสู่ระบบหรือไม่ และ roles ของผู้ใช้ที่เข้าสู่ระบบ หรือเสนอ fields มากหรือน้อยขึ้นอยู่กับ property อื่นๆ เช่น การที่ผู้ใช้ชำระเงินสำหรับสมาชิก PRO หรือไม่

Types ไม่รู้ล่วงหน้าว่าจะ resolve fields ใด แต่ field resolvers จะผูกตัวเองกับ type resolvers โดยใช้ publish-subscribe pattern และ field resolvers สามารถ override field resolvers อื่นได้ ฟีเจอร์นี้ทำให้ API ขยายได้ง่ายมาก ช่วยให้เราสามารถมีโค้ดทั่วไปสำหรับ API และปรับแต่งในระดับ application สำหรับ client หรือโปรเจกต์เฉพาะ

field หนึ่งๆ สามารถถูกประมวลผลโดยไม่ใช่แค่ field resolver เดียว แต่หลาย field resolvers: field resolver แต่ละตัวใน chain สามารถตัดสินใจในรันไทม์ว่าจะประมวลผล field หรือไม่ตาม property บางอย่าง หรือส่งต่อไปตาม chain ตัวอย่างเช่น field resolver พิเศษอาจถูกใช้เฉพาะเมื่อมีการส่ง field argument "source: testing" เพื่อให้สามารถทดสอบในบางเว็บไซต์ใน production ก่อนการเผยแพร่ทั่วไป กลยุทธ์เดียวกันนี้ยังช่วยให้สามารถแก้ไขบั๊กอย่างรวดเร็วสำหรับ client หรือสภาพแวดล้อมเฉพาะโดยไม่เสี่ยงต่อผลข้างเคียงที่ไม่ตั้งใจในที่อื่น

Types และ interfaces สามารถถูกกำหนด namespace โดยอัตโนมัติเพื่อหลีกเลี่ยงการชนกับ 3rd parties