แนวทางการออกแบบ RESTful API ประเภทของคำขอ HTTP และปรัชญา REST ตัวอย่าง Restful API

05.01.2024 ผู้ประกอบการมือถือ

ในบทความนี้ ฉันจะแบ่งปันประสบการณ์ของฉันในการออกแบบ RESTful API - โดยใช้ตัวอย่างที่เฉพาะเจาะจง ฉันจะแสดงวิธีการสร้างบริการที่เรียบง่ายอย่างน้อยอย่างสวยงาม นอกจากนี้เรายังจะพูดถึงว่า API คืออะไรและเหตุใดจึงมีความจำเป็น เราจะพูดถึงพื้นฐานของ REST - เราจะหารือถึงวิธีการนำไปใช้ เรามาพูดถึงแนวทางปฏิบัติพื้นฐานของเว็บที่ขึ้นอยู่กับและไม่ขึ้นอยู่กับเทคโนโลยีนี้ นอกจากนี้ เรายังจะได้เรียนรู้วิธีเขียนเอกสารที่ดีโดยใช้ความพยายามเพียงเล็กน้อย และดูว่ามีวิธีการกำหนดเวอร์ชันใดบ้างสำหรับ RESTful API

ส่วนที่ 1 ทฤษฎี

ดังที่เราทุกคนทราบกันดีว่า API คืออินเทอร์เฟซการเขียนโปรแกรมแอปพลิเคชัน ซึ่งเป็นชุดของกฎและกลไกที่แอปพลิเคชันหรือส่วนประกอบหนึ่งโต้ตอบกับแอปพลิเคชันอื่น

เหตุใด API ที่ดีจึงมีความสำคัญ

  • ใช้งานง่ายและรองรับ- API ที่ดีนั้นง่ายต่อการใช้งานและบำรุงรักษา
  • การแปลงที่ดีในหมู่นักพัฒนา- หากทุกคนชอบ API ของคุณ ลูกค้าและผู้ใช้รายใหม่จะมาหาคุณ
  • เพิ่มความนิยมในบริการของคุณ- ยิ่งมีผู้ใช้ API มากเท่าใด ความนิยมในบริการของคุณก็จะยิ่งสูงขึ้นเท่านั้น
  • ฉนวนส่วนประกอบที่ดีขึ้น- ยิ่งโครงสร้าง API ดีเท่าไร การแยกส่วนประกอบก็จะยิ่งดีขึ้นเท่านั้น
  • ความประทับใจที่ดีต่อสินค้า- API ก็เหมือนกับ UI ของนักพัฒนา นี่คือสิ่งที่นักพัฒนาให้ความสนใจเป็นอันดับแรกเมื่อพบกับผลิตภัณฑ์ หาก API มีลักษณะโค้ง ในฐานะผู้เชี่ยวชาญด้านเทคนิค คุณจะไม่แนะนำให้บริษัทต่างๆ ใช้ผลิตภัณฑ์ดังกล่าวโดยการซื้อบางอย่างจากบุคคลที่สาม

มาดูกันว่ามี API ประเภทใดบ้าง

ประเภทของ API ตามวิธีการนำไปใช้:

  • API บริการเว็บ
    • XML-RPC และ JSON-RPC
  • WebSockets API
  • API ที่ใช้ไลบรารี
    • จาวาสคริปต์
  • API ตามคลาส
    • C# API
  • ฟังก์ชั่นและกิจวัตรของระบบปฏิบัติการ
    • การเข้าถึงระบบไฟล์
    • การเข้าถึงส่วนต่อประสานกับผู้ใช้
  • API ระยะไกลของวัตถุ
    • คอร์บา
    • .Net ระยะไกล
  • API ฮาร์ดแวร์
    • การเร่งความเร็ววิดีโอ (OpenCL...)
    • ฮาร์ดดิสก์ไดรฟ์
    • บัส PCI


ดังที่เราเห็น Web API ประกอบด้วย XML-RPC และ JSON-RPC, SOAP และ REST

RPC (การเรียกขั้นตอนระยะไกล) เป็นแนวคิดที่เก่ามาก โดยผสมผสานโปรโตคอลโบราณ กลาง และสมัยใหม่เข้าด้วยกัน ซึ่งช่วยให้คุณสามารถเรียกใช้วิธีการในแอปพลิเคชันอื่นได้ XML-RPC เป็นโปรโตคอลที่ปรากฏในปี 1998 หลังจากการถือกำเนิดของ XML ไม่นาน Microsoft ได้รับการสนับสนุนในตอนแรก แต่ในไม่ช้า Microsoft ก็เปลี่ยนมาใช้ SOAP โดยสิ้นเชิง ดังนั้นเราจะไม่พบคลาสที่รองรับโปรโตคอลนี้ใน .Net Framework อย่างไรก็ตามเรื่องนี้ XML-RPC ยังคงมีชีวิตอยู่จนถึงทุกวันนี้ในภาษาต่างๆ (โดยเฉพาะ PHP) - เห็นได้ชัดว่ามันได้รับความรักจากนักพัฒนาในเรื่องความเรียบง่าย

SOAP ยังปรากฏในปี 1998 ผ่านความพยายามของ Microsoft ได้รับการประกาศให้เป็นการปฏิวัติในโลกซอฟต์แวร์ นี่ไม่ได้เป็นการบอกว่าทุกอย่างเป็นไปตามแผนของ Microsoft: มีการวิพากษ์วิจารณ์มากมายเนื่องจากความซับซ้อนและความหนักเบาของโปรโตคอล ในขณะเดียวกันก็มีคนมองว่า SOAP เป็นความก้าวหน้าที่แท้จริง โปรโตคอลยังคงพัฒนาและผลิตข้อกำหนดใหม่ๆ มากมาย จนกระทั่งในปี 2003 W3C ได้อนุมัติ SOAP 1.2 เป็นคำแนะนำ ซึ่งยังคงเป็นเวอร์ชันล่าสุด กลุ่มผลิตภัณฑ์ SOAP กลายเป็นผลิตภัณฑ์ที่น่าประทับใจ: WS-Addressing, WS-Enumeration, WS-Eventing, WS-Transfer, WS-Trust, WS-Federation, Web Single Sign-On

จากนั้นแนวทางที่เรียบง่ายจริงๆ ก็ปรากฏขึ้น - REST ตัวย่อ REST ย่อมาจาก การถ่ายโอนสถานะการเป็นตัวแทน - "การถ่ายโอนสถานะการเป็นตัวแทน" หรือที่กล่าวได้ดีกว่าคือการนำเสนอข้อมูลในรูปแบบที่สะดวกสำหรับลูกค้า คำว่า "REST" ได้รับการประกาศเกียรติคุณโดย Roy Fielding ในปี 2000 แนวคิดพื้นฐานของ REST คือการโทรไปยังบริการแต่ละครั้งจะนำแอปพลิเคชันไคลเอนต์ไปสู่สถานะใหม่ โดยพื้นฐานแล้ว REST ไม่ใช่โปรโตคอลหรือมาตรฐาน แต่เป็นแนวทาง ซึ่งเป็นรูปแบบสถาปัตยกรรมสำหรับการออกแบบ API

หลักการของ REST คืออะไร?

  • สถาปัตยกรรมไคลเอ็นต์-เซิร์ฟเวอร์- หากไม่มีสิ่งนี้ REST ก็คิดไม่ถึง
  • ข้อมูลใด ๆ ที่เป็นทรัพยากร.
  • ทรัพยากรใด ๆ มีรหัสซึ่งสามารถดึงข้อมูลออกมาได้
  • ทรัพยากรสามารถเชื่อมโยงถึงกันได้- สำหรับสิ่งนี้ ไม่ว่าจะเป็น ID หรือตามที่แนะนำบ่อยกว่านั้น ลิงก์จะถูกส่งไปเป็นส่วนหนึ่งของการตอบกลับ แต่ฉันยังไม่ถึงจุดที่ทุกอย่างดีจนฉันสามารถใช้ลิงก์ได้อย่างง่ายดาย
  • ใช้วิธีการ HTTP มาตรฐาน(GET, POST, PUT, DELETE) - เนื่องจากมีการรวมไว้ในโปรโตคอลแล้ว เราจึงสามารถใช้สิ่งเหล่านี้เพื่อสร้างกรอบงานสำหรับการโต้ตอบกับเซิร์ฟเวอร์ของเรา
  • เซิร์ฟเวอร์ไม่ได้จัดเก็บสถานะ- หมายความว่าเซิร์ฟเวอร์ไม่ได้แยกการโทรหนึ่งออกจากอีกสายหนึ่ง และไม่ได้จัดเก็บเซสชันทั้งหมดไว้ในหน่วยความจำ หากคุณมีระบบคลาวด์ที่ปรับขนาดได้ หรือเซิร์ฟเวอร์ฟาร์มบางประเภทที่ใช้บริการของคุณ ก็ไม่จำเป็นต้องตรวจสอบความสอดคล้องของสถานะของบริการเหล่านี้ระหว่างโหนดทั้งหมดที่คุณมี สิ่งนี้ช่วยลดความยุ่งยากในการปรับขนาดได้มาก - เมื่อเพิ่มโหนดอื่น ทุกอย่างทำงานได้ดี

ทำไม REST ถึงดี?

  • มันง่ายมาก!
  • เราจะนำมาตรฐานที่มีอยู่กลับมาใช้ใหม่ซึ่งมีการใช้งานมาอย่างยาวนานและถูกนำไปใช้กับอุปกรณ์มากมาย
  • ส่วนที่เหลือจะขึ้นอยู่กับ HTTP=> สินค้าทั้งหมดมีจำหน่าย:
    • เก็บเอาไว้.
    • การปรับขนาด
    • ต้นทุนค่าโสหุ้ยขั้นต่ำ
    • รหัสข้อผิดพลาดมาตรฐาน
  • แพร่ระบาดได้ดีมาก(แม้แต่อุปกรณ์ IoT ก็รู้วิธีเรียกใช้ HTTP อยู่แล้ว)
โซลูชั่นที่ดีที่สุด (ไม่ขึ้นอยู่กับเทคโนโลยี)
อะไรคือโซลูชั่นที่ดีที่สุดในโลกสมัยใหม่ที่ไม่เกี่ยวข้องกับการใช้งานเฉพาะด้าน? ฉันแนะนำให้ใช้โซลูชันเหล่านี้อย่างแน่นอน:
  • SSL ทุกที่- สิ่งที่สำคัญที่สุดในบริการของคุณ เพราะหากไม่มีการอนุญาต SSL และการรับรองความถูกต้องจะไม่มีความหมาย
  • เอกสารประกอบและการกำหนดเวอร์ชันบริการ - ตั้งแต่วันแรกของการทำงาน
  • วิธีการ POST และ PUT จะต้องกลับมาส่งคืนออบเจ็กต์ที่เปลี่ยนแปลงหรือสร้าง - ซึ่งจะช่วยลดเวลาในการเข้าถึงบริการลงครึ่งหนึ่ง
  • รองรับการกรอง การเรียงลำดับ และการแบ่งหน้า- เป็นที่พึงปรารถนาอย่างยิ่งว่าสิ่งนี้จะเป็นมาตรฐานและทำงานนอกกรอบ
  • รองรับ MediaType- MediaType เป็นวิธีบอกเซิร์ฟเวอร์ว่าคุณต้องการให้เนื้อหาอยู่ในรูปแบบใด หากคุณใช้งาน Web API มาตรฐานใดๆ และเข้าถึงจากเบราว์เซอร์ API ดังกล่าวจะให้ XML แก่คุณ และหากคุณเข้าถึงผ่านบุรุษไปรษณีย์ API ก็จะส่งคืน JSON
  • พริตตี้พริ้นท์ & gzip- อย่าย่อขนาดคำขอและอย่าทำการบีบอัดสำหรับ JSON (การตอบกลับที่มาจากเซิร์ฟเวอร์) ค่าใช้จ่ายใน Prettyprint อยู่ในหน่วยเปอร์เซ็นต์ ซึ่งสามารถเห็นได้หากคุณดูว่าใช้แท็บมากน้อยเพียงใดเมื่อเทียบกับขนาดข้อความทั้งหมด หากคุณลบแท็บและส่งทุกอย่างในบรรทัดเดียว คุณจะเบื่อหน่ายกับการดีบัก สำหรับ gzip นั้นให้ประโยชน์มากกว่าหลายเท่า โดยเฉพาะอย่างยิ่ง ฉันขอแนะนำให้ใช้ทั้ง Prettyprint และ gzip
  • ใช้เฉพาะกลไกการแคชมาตรฐาน (ETag) และ Last-Modified (วันที่แก้ไขล่าสุด)- พารามิเตอร์ทั้งสองนี้เพียงพอสำหรับเซิร์ฟเวอร์สำหรับไคลเอนต์ที่จะเข้าใจว่าเนื้อหาไม่จำเป็นต้องอัปเดต ไม่มีประโยชน์ที่จะประดิษฐ์บางอย่างของคุณเองที่นี่
  • ใช้รหัสข้อผิดพลาด HTTP มาตรฐานเสมอ- มิฉะนั้น วันหนึ่งคุณจะต้องอธิบายให้ใครสักคนฟังว่าทำไมคุณถึงตัดสินใจว่าลูกค้าต้องตีความข้อผิดพลาด 419 ในโครงการของคุณเหมือนกับที่คุณคิดไว้ด้วยเหตุผลบางประการ สิ่งนี้ไม่สะดวกและน่าเกลียด - ลูกค้าจะไม่ขอบคุณสำหรับสิ่งนี้!
คุณสมบัติของวิธี HTTP

วันนี้เราจะพูดถึง GET, POST, PUT, DELETE เท่านั้น

พูดสั้น ๆ เกี่ยวกับสิ่งอื่น ๆ ที่นำเสนอในตาราง OPTIONS - รับการตั้งค่าความปลอดภัย HEAD - รับส่วนหัวโดยไม่มีเนื้อหาข้อความ PATCH - การเปลี่ยนแปลงเนื้อหาบางส่วน

อย่างที่คุณเห็น วิธีการทั้งหมดยกเว้น POST ที่แสดงในตารางนั้นเป็น idempotent Idempotency คือความสามารถในการทำการเรียกบริการเดียวกันหลายครั้ง และการตอบกลับจะเหมือนกันในแต่ละครั้ง กล่าวอีกนัยหนึ่ง ไม่สำคัญว่าคุณดำเนินการนี้ด้วยเหตุผลใดหรือกี่ครั้ง สมมติว่าคุณกำลังทำการเปลี่ยนแปลงการกระทำของวัตถุ (PUT) และคุณได้รับข้อผิดพลาด คุณไม่รู้ว่าอะไรเป็นสาเหตุ และ ณ เวลาใด คุณไม่รู้ว่าวัตถุนั้นเปลี่ยนแปลงไปหรือไม่ แต่ด้วยความสามารถในการระบุตัวตน คุณจึงรับประกันได้ว่าจะดำเนินการนี้อีกครั้ง เพื่อให้ลูกค้ามั่นใจในความสมบูรณ์ของข้อมูลของตนได้

“ปลอดภัย” หมายความว่าการเข้าถึงเซิร์ฟเวอร์จะไม่เปลี่ยนแปลงเนื้อหา ดังนั้น GET สามารถเรียกได้หลายครั้งแต่จะไม่เปลี่ยนแปลงเนื้อหาใดๆ หากต้องเปลี่ยนเนื้อหา เนื่องจาก GET สามารถแคชได้ คุณจะต้องต่อสู้กับการแคชและสร้างพารามิเตอร์ที่ยุ่งยากบางอย่าง

ส่วนที่ 2 การปฏิบัติ
การเลือกเทคโนโลยี

ตอนนี้เราเข้าใจวิธีการทำงานของ REST แล้ว เราก็เริ่มเขียน RESTful API ซึ่งเป็นบริการที่เป็นไปตามหลักการของ REST ได้เลย เริ่มจากการเลือกเทคโนโลยีกันก่อน

ตัวเลือกแรก - บริการ WCF- ทุกคนที่ทำงานกับเทคโนโลยีนี้มักจะไม่ต้องการกลับไปใช้อีกต่อไป - มีข้อเสียร้ายแรงและมีข้อดีบางประการ:
– webHttpBinding เท่านั้น (ทำไมถึงเหลือล่ะ..)
– รองรับเฉพาะ HTTP Get & POST เท่านั้น (นั่นคือทั้งหมด)
+ รูปแบบต่างๆ XML, JSON, ATOM

ตัวเลือกที่สอง - เว็บเอพีไอ- ในกรณีนี้มีข้อดีที่ชัดเจน:
+ ง่ายมาก
+ โอเพ่นซอร์ส
+ คุณสมบัติ HTTP ทั้งหมด
+ คุณสมบัติ MVC ทั้งหมด
+ น้ำหนักเบา
+ รองรับรูปแบบมากมาย

แน่นอนว่าเราเลือก Web API ตอนนี้เรามาเลือกโฮสติ้งที่เหมาะสมสำหรับ Web API กันดีกว่า

การเลือกโฮสติ้งสำหรับ Web API

มีตัวเลือกค่อนข้างน้อยที่นี่:

  • ASP.NET MVC (ตัวเก่าที่ดี)
  • Azure (โครงสร้างคลาวด์)
  • OWIN - เปิดเว็บอินเตอร์เฟสสำหรับ .NET (การพัฒนาใหม่จาก Microsoft)
  • โฮสต์เอง
โอวีไอ
โอวินไม่ใช่แพลตฟอร์มหรือไลบรารี แต่เป็นข้อกำหนดที่จะลบการเชื่อมต่อที่แข็งแกร่งของเว็บแอปพลิเคชันออกจากการใช้งานเซิร์ฟเวอร์ อนุญาตให้แอปพลิเคชันทำงานบนแพลตฟอร์มใด ๆ ที่รองรับ OWIN โดยไม่ต้องดัดแปลง ในความเป็นจริง ข้อมูลจำเพาะนั้นง่ายมาก - เป็นเพียง "พจนานุกรม" ของพารามิเตอร์และค่าของมัน พารามิเตอร์พื้นฐานถูกกำหนดไว้ในข้อกำหนด

OWIN ย่อมาจากโครงสร้างที่เรียบง่ายมาก:

ตามแผนภาพเราจะเห็นว่ามีโฮสต์ซึ่งมีเซิร์ฟเวอร์ที่รองรับ "พจนานุกรม" ที่เรียบง่ายมากซึ่งประกอบด้วยรายการ "พารามิเตอร์ - ค่า" โมดูลทั้งหมดที่เชื่อมต่อกับเซิร์ฟเวอร์นี้ได้รับการกำหนดค่าด้วยวิธีนี้ เซิร์ฟเวอร์ที่รองรับสัญญานี้ซึ่งเชื่อมโยงกับแพลตฟอร์มเฉพาะ สามารถรับรู้พารามิเตอร์เหล่านี้ทั้งหมดและเริ่มต้นโครงสร้างพื้นฐานตามลำดับ ปรากฎว่าหากคุณเขียนบริการที่ทำงานร่วมกับ OWIN คุณสามารถถ่ายโอนระหว่างแพลตฟอร์มได้อย่างอิสระโดยไม่ต้องเปลี่ยนรหัสและใช้สิ่งเดียวกันบน OS อื่น ๆ

คาทานา- การใช้งาน OWIN จาก Microsoft อนุญาตให้คุณโฮสต์แอสเซมบลีของ OWIN ใน IIS นี่คือสิ่งที่ดูเหมือน ง่ายมาก:

Namespace RestApiDemo (การเริ่มต้นคลาสสาธารณะ (การกำหนดค่าโมฆะสาธารณะ (แอป IAppBuilder) ( var config = new HttpConfiguration(); config.MapHttpAttributeRoutes(); app.UseWebApi(config); ) ) )

คุณระบุว่าสตาร์ทอัพของคุณคือคลาสใด นี่เป็น dll ธรรมดาที่ IIS เลือกขึ้นมา ตัวกำหนดค่าเรียกว่า รหัสนี้เพียงพอที่จะทำให้ทุกอย่างทำงานได้

การออกแบบอินเทอร์เฟซ
ตอนนี้เรามาออกแบบอินเทอร์เฟซและดูว่าทุกอย่างควรมีลักษณะอย่างไรและควรปฏิบัติตามกฎเกณฑ์ใดบ้าง ทรัพยากรทั้งหมดใน REST เป็นคำนาม เป็นสิ่งที่สามารถสัมผัสและสัมผัสได้

ตัวอย่างเช่น ลองใช้โมเดลง่ายๆ กับตารางรถไฟที่สถานีต่างๆ นี่คือตัวอย่างของคำขอ REST แบบธรรมดา:

  • เอนทิตี API รูท (อิสระ):
    • GET /stations - รับทุกสถานี
    • GET /stations/123 - รับข้อมูลเกี่ยวกับสถานีที่มี ID = 123
    • GET /trains - ตารางเวลารถไฟทั้งหมด
  • เอนทิตีที่ขึ้นต่อกัน (จากรูท):
    • GET /stations/555/departures - รถไฟออกจากสถานี 555
คอนโทรลเลอร์

ดังนั้นเราจึงมีสถานี และตอนนี้เราต้องเขียนตัวควบคุมง่ายๆ:

RailwayStationsController ระดับสาธารณะ: ApiController ( IEnumerable. สาธารณะ GetAll() ( return testData; ) RailwayStationModel testData = /*การกำหนดค่าเริ่มต้นที่นี่*/ )

นี่คือการกำหนดเส้นทางตามคุณลักษณะ ที่นี่เราระบุชื่อของคอนโทรลเลอร์และขอรายการ (ในกรณีนี้คือข้อมูลการทดสอบแบบสุ่ม)

โอดาต้า (www.odata.org)

ทีนี้ลองจินตนาการว่าคุณมีข้อมูลบนไคลเอนต์มากกว่าที่คุณต้องการ (การพกพาเกินร้อยข้อมูลเป็นเรื่องยาก) ในขณะเดียวกัน แน่นอนว่า คุณคงไม่อยากเขียนเลขหน้าด้วยตัวเอง มีวิธีง่ายๆ แทน นั่นคือการใช้ OData เวอร์ชัน Lightweight ซึ่งได้รับการสนับสนุนโดย Web API

RailwayStationsController ระดับสาธารณะ: ApiController (public IQueryable GetAll() ( return testData.AsQueryable(); ) RailwayStationModel testData = /*การกำหนดค่าเริ่มต้นที่นี่*/ )

IQueryable ช่วยให้คุณใช้กลไกการกรองและการจัดการข้อมูลที่เรียบง่ายแต่มีประสิทธิภาพหลายอย่างในฝั่งไคลเอ็นต์ สิ่งเดียวที่คุณต้องทำคือเชื่อมต่อแอสเซมบลี OData จาก NuGet ระบุ EnableQuery และส่งคืนอินเทอร์เฟซ iQueryable

ข้อแตกต่างที่สำคัญระหว่างเวอร์ชันน้ำหนักเบาและเวอร์ชันเต็มก็คือ ไม่มีตัวควบคุมที่ส่งคืนข้อมูลเมตา OData ที่ครบถ้วนสมบูรณ์จะเปลี่ยนคำตอบเล็กน้อย (โดยล้อมโมเดลที่คุณจะส่งคืนใน wrapper พิเศษ) และสามารถส่งคืนแผนผังที่เกี่ยวข้องของวัตถุที่คุณต้องการมอบให้ นอกจากนี้ OData เวอร์ชัน Lightweight ไม่สามารถทำสิ่งต่างๆ เช่น เข้าร่วม นับ ฯลฯ ได้

พารามิเตอร์แบบสอบถาม

นี่คือสิ่งที่คุณสามารถทำได้:

  • $filter - กรองตามชื่อ เป็นต้น สามารถดูฟังก์ชันทั้งหมดได้บนเว็บไซต์ OData ซึ่งมีประโยชน์มากและช่วยให้คุณสามารถจำกัดตัวอย่างได้อย่างมาก
  • $select เป็นสิ่งที่สำคัญมาก หากคุณมีคอลเลกชันขนาดใหญ่และวัตถุทั้งหมดมีความหนา แต่ในขณะเดียวกันคุณต้องสร้างดรอปดาวน์บางประเภทซึ่งไม่มีอะไรนอกจาก ID และชื่อที่คุณต้องการแสดง ฟังก์ชันนี้จะช่วยซึ่ง จะทำให้การโต้ตอบกับเซิร์ฟเวอร์ง่ายขึ้นและเร็วขึ้น
  • $orderby - การเรียงลำดับ
  • $top และ $skip - จำกัดตัวอย่าง

นี่ก็เพียงพอแล้วที่จะหลีกเลี่ยงการคิดค้นล้อใหม่ด้วยตัวเอง ไลบรารี JS มาตรฐานเช่น Breeze สามารถทำทั้งหมดนี้ได้

แอตทริบิวต์ EnableQuery
ในความเป็นจริง OData เป็นสิ่งที่สามารถยิงตัวเองเข้าที่เท้าได้อย่างง่ายดาย หากคุณมีบันทึกหลายล้านรายการในตารางของคุณ และคุณจำเป็นต้องดึงบันทึกเหล่านั้นจากเซิร์ฟเวอร์ไปยังไคลเอนต์ มันจะเป็นเรื่องยาก และหากมีคำขอดังกล่าวจำนวนมาก ก็จะเป็นอันตรายถึงชีวิตอย่างแน่นอน

ในกรณีเช่นนี้แอตทริบิวต์ EnableQuery (ดูโค้ดด้านบน) มีชุดพารามิเตอร์ที่คุณสามารถจำกัดได้มาก: อย่าให้แถวมากเกินความจำเป็น ไม่อนุญาตให้เข้าร่วม การดำเนินการทางคณิตศาสตร์ ฯลฯ ในเวลาเดียวกัน เขียนเองไม่ต้องการอะไร

  • ตัวดำเนินการทางคณิตศาสตร์ที่อนุญาต
  • ฟังก์ชันที่อนุญาต
  • ตัวดำเนินการลอจิคัลที่อนุญาต
  • AllowedOrderByProperties
  • AllowedQueryOptions
  • เปิดใช้งานการกำหนดพารามิเตอร์คงที่
  • มั่นใจในการสั่งซื้อที่มั่นคง
  • จัดการ NullPropagation
  • MaxAnyAllExpressionDepth
  • ความลึกของการขยายตัวสูงสุด
  • MaxNodeCount
  • MaxOrderByNodeCount
  • MaxSkip
  • แม็กซ์ท็อป
  • ขนาดหน้า

ตัวควบคุมขึ้นอยู่กับ
ต่อไปนี้คือตัวอย่างคำขอ REST ที่ง่ายที่สุด:

  • GET /stations – รับทุกสถานี
  • GET /trains – ตารางเวลารถไฟทั้งหมด
  • GET /สถานี/555/ขาเข้า
  • GET /สถานี/555/ออกเดินทาง

สมมติว่าเรามีสถานี 555 และเราต้องการทราบข้อมูลขาเข้าและขาออกทั้งหมด แน่นอนว่าต้องใช้เอนทิตีที่นี่ซึ่งขึ้นอยู่กับเอนทิตีของสถานี แต่จะทำสิ่งนี้ในคอนโทรลเลอร์ได้อย่างไร? หากเราทำทั้งหมดนี้ด้วยคุณลักษณะการกำหนดเส้นทางและรวมไว้ในคลาสเดียว ก็ชัดเจนว่าในตัวอย่างนี้ไม่มีปัญหาใดๆ แต่ถ้าคุณมีเอนทิตีที่ซ้อนกันหลายสิบรายการและความลึกเพิ่มมากขึ้น เอนทิตีทั้งหมดก็จะเติบโตเป็นรูปแบบที่ไม่รองรับ

และมีวิธีแก้ไขง่ายๆ - คุณสามารถสร้างตัวแปรในแอตทริบิวต์การกำหนดเส้นทางในคอนโทรลเลอร์ได้:

TrainsFromController ระดับสาธารณะ: TrainsController (สาธารณะ IQueryable GetAll(int สถานี) ( กลับ GetAllTrips().Where(x =>

ดังนั้น ให้วางเอนทิตีที่ขึ้นต่อกันทั้งหมดไว้ในคอนโทรลเลอร์ที่แยกต่างหาก มีกี่คนไม่สำคัญเลยเนื่องจากพวกเขาอาศัยอยู่แยกกัน จากมุมมองของ Web API คอนโทรลเลอร์ต่างๆ จะถูกรับรู้ - ดูเหมือนว่าระบบจะไม่รู้ว่าพวกมันขึ้นอยู่กับพวกมัน แม้ว่าใน URL จะมีลักษณะเช่นนั้นก็ตาม

ปัญหาเดียวที่เกิดขึ้นคือที่นี่เรามี "สถานี" และก่อนหน้านั้นก็มี "สถานี" หากคุณเปลี่ยนแปลงบางสิ่งในที่หนึ่งและไม่เปลี่ยนแปลงอะไรเลยในอีกที่หนึ่ง ก็จะไม่มีอะไรเกิดขึ้น อย่างไรก็ตาม มีวิธีแก้ไขง่ายๆ คือการใช้งาน ค่าคงที่การกำหนดเส้นทาง:

คลาสคงที่สาธารณะ TrainsFromControllerRoutes (สตริง const สาธารณะ BasePrefix = RailwayStationsControllerRoutes.BasePrefix + "/(station:int)/departures"; สตริง const สาธารณะ GetById = "(id:int)"; )

จากนั้นตัวควบคุมที่ขึ้นต่อกันจะมีลักษณะดังนี้:

TrainsFromController ระดับสาธารณะ: TrainsController (สาธารณะ IQueryable GetAll(int สถานี) ( return GetAll().Where(x => x.OriginRailwayStationId == station); ) )

คุณสามารถดำเนินการง่ายๆ สำหรับตัวควบคุมที่ต้องพึ่งพาได้ - คุณเพียงแค่คำนวณและคำนวณเส้นทางด้วยตัวเอง จากนั้นคุณจะไม่ทำผิดพลาด นอกจากนี้สิ่งเหล่านี้ยังมีประโยชน์สำหรับการทดสอบอีกด้วย หากคุณต้องการเขียนการทดสอบแล้วต้องการจัดการ และไม่ดำเนินการทดสอบหลายล้านครั้งในแต่ละครั้ง และแก้ไขบรรทัดทั้งหมดที่ระบุ URL ที่เกี่ยวข้องเหล่านี้ คุณสามารถใช้ค่าคงที่เหล่านี้ได้เช่นกัน เมื่อคุณเปลี่ยน ข้อมูลของคุณจะเปลี่ยนไปทุกที่ มันสะดวกสบายมาก

CRUD
ดังนั้นเราจึงได้พูดคุยกันว่าการดำเนินการ GET ที่ง่ายที่สุดอาจมีหน้าตาเป็นอย่างไร ทุกคนเข้าใจวิธีการทำ GET เดียว แต่นอกเหนือจากนี้ เรายังต้องหารือเกี่ยวกับปฏิบัติการอีกสามรายการ
  • POST – สร้างเอนทิตีใหม่
    • POST /Stations – คำอธิบาย JSON ของเอนทิตีทั้งหมด การดำเนินการเพิ่มเอนทิตีใหม่ให้กับคอลเลกชัน
    • ส่งคืนเอนทิตีที่สร้างขึ้น (ประการแรกเพื่อไม่ให้มีการเดินทางไปยังเซิร์ฟเวอร์สองครั้ง และประการที่สอง ดังนั้นหากจำเป็น ให้ส่งคืนพารามิเตอร์ที่คำนวณในออบเจ็กต์นี้และที่คุณต้องการบนไคลเอนต์จากเซิร์ฟเวอร์)
  • PUT - เปลี่ยนเอนทิตี
    • PUT /Stations/12 - เปลี่ยนเอนทิตีด้วย ID = 12 JSON ที่เข้ามาในพารามิเตอร์จะถูกเขียนทับ
    • ส่งกลับเอนทิตีที่ถูกแก้ไข เส้นทางที่ถูกนำไปใช้หลายครั้งควรนำระบบไปสู่สถานะเดียวกัน
  • ลบ
    • DELETE /Stations/12 - ลบเอนทิตีที่มี ID = 12

ตัวอย่าง CRUD เพิ่มเติม:

  • POST /สถานี - เพิ่มสถานี
  • POST /Stations/1/Departures - เพิ่มข้อมูลเกี่ยวกับการออกเดินทางจากสถานี 1
  • DELETE /Stations/1/Departures/14 - ลบบันทึกการออกจากสถานี 1
  • GET /Stations/33/Departures/10/Tickets - รายการตั๋วที่จำหน่ายสำหรับการเดินทางขาออก 10 จากสถานี 33

สิ่งสำคัญคือต้องเข้าใจว่าโหนดจำเป็นต้องมีเอนทิตีบางอย่าง ซึ่งเป็นสิ่งที่ "สัมผัสได้" (ตั๋ว รถไฟ ข้อเท็จจริงของการออกเดินทางของรถไฟ ฯลฯ)

ต่อต้านรูปแบบ
นี่คือตัวอย่างสิ่งที่ไม่ควรทำ:
  • GET /Stations/?op=departure&train=11
    ในที่นี้สตริงการสืบค้นไม่ได้ใช้เพื่อส่งข้อมูลเท่านั้น แต่ยังใช้สำหรับการดำเนินการด้วย
  • รับ /สถานี/ลบทั้งหมด
    นี่คือตัวอย่างในชีวิตจริง ที่นี่เราทำ GET ไปยังที่อยู่นี้ และในทางทฤษฎีแล้ว ควรลบเอนทิตีทั้งหมดออกจากคอลเลกชัน - ด้วยเหตุนี้ จึงทำงานอย่างคาดเดาไม่ได้เนื่องจากการแคช
  • POST /GetUserActivity
    นี่คือ GET จริงๆ ซึ่งเขียนเป็น POST จำเป็นต้องใช้ POST เนื่องจากพารามิเตอร์คำขอในร่างกาย แต่ GET ไม่สามารถส่งผ่านสิ่งใดไปยังเนื้อหาได้ - GET สามารถส่งผ่านไปยังสตริงการสืบค้นเท่านั้น GET ไม่รองรับเนื้อหาตามมาตรฐานด้วยซ้ำ
  • POST /สถานี/สร้าง
    ที่นี่การกระทำถูกระบุเป็นส่วนหนึ่งของ URL ซึ่งเป็นการกระทำที่ซ้ำซ้อน
การออกแบบ API
สมมติว่าคุณมี API ที่คุณต้องการนำเสนอให้กับผู้คน และคุณมีโมเดลโดเมน เอนทิตี API เกี่ยวข้องกับโมเดลโดเมนอย่างไร ใช่ พวกเขาไม่ได้เชื่อมโยงกันแต่อย่างใด ไม่จำเป็นสำหรับสิ่งนี้: สิ่งที่คุณทำใน API ไม่เกี่ยวข้องกับโมเดลโดเมนภายในของคุณ

อาจเกิดคำถามว่า จะออกแบบ API อย่างไรถ้าไม่ใช่ CRUD? ในการดำเนินการนี้ เราจะบันทึกการกระทำใดๆ ไว้เป็นคำสั่งเปลี่ยนแปลง เราบันทึก อ่าน ลบคำสั่ง GET ตรวจสอบสถานะของคำสั่งนั้นๆ รับจากชุดคำสั่ง - คุณจะได้รับรายการคำสั่งทั้งหมดที่คุณส่งไปยังเอนทิตีเฉพาะ

โมเดลโดเมน
เราจะพูดถึงความเชื่อมโยงระหว่างโมเดลโดเมนและออบเจ็กต์ ในตัวอย่างนี้ เรามีโรงแรม (โรงแรม) มีการจอง (Reservation) ห้อง (ห้อง) และอุปกรณ์ (Device) ที่เกี่ยวข้องกัน ในโครงการของเรา สิ่งนี้ทำให้สามารถควบคุมห้องผ่านอุปกรณ์เหล่านี้ได้

แต่นี่คือปัญหา: อุปกรณ์นั้นเป็นสิ่งมีชีวิตของตัวเอง และไม่ชัดเจนว่าจะแยกอุปกรณ์ออกจากโรงแรมอย่างไร แต่จริงๆ แล้วการแยกโรงแรมและอุปกรณ์ต่างๆ นั้นง่ายมาก - DDD จะช่วยได้ ก่อนอื่น คุณต้องพิจารณาว่าขอบเขตของพื้นที่โดเมนอยู่ที่ไหน และขอบเขตของหน่วยงานที่รับผิดชอบความสอดคล้องของระบบอยู่ที่ใด

บริบทที่มีขอบเขต (BC)
บริบทที่มีขอบเขต (โดเมนย่อยที่แยกได้) - อันที่จริงแล้วคือชุดของอ็อบเจ็กต์ที่เป็นอิสระจากกันและมีโมเดลที่เป็นอิสระอย่างสมบูรณ์ (ต่างกัน) ในตัวอย่าง เราสามารถแยกโรงแรมและอุปกรณ์ออกเป็นสอง BC ที่แตกต่างกันได้ โดยไม่ได้เชื่อมต่อถึงกัน แต่มีการทำซ้ำ เอนทิตีเพิ่มเติม (AttachedDevice) ปรากฏขึ้น:

ที่นี่เรามีการนำเสนออุปกรณ์เดียวกันที่แตกต่างกัน และไม่มีอะไรผิดปกติกับสิ่งนั้น

ใน DDD เส้นทางรวมคือเอนทิตีที่เป็นเจ้าของรายการย่อยทั้งหมด นี่คือจุดสูงสุดของต้นไม้ของเรา (โรงแรม); บางสิ่งบางอย่างโดยที่ทุกสิ่งทุกอย่างสามารถดึงออกมาได้ แต่คุณไม่สามารถใช้ AttachedDevice แบบนั้นได้ - มันไม่มีอยู่จริงและมันไม่สมเหตุสมผลเลย ในทำนองเดียวกัน ชั้นเรียนห้องและการสำรองห้องพักก็ไม่สมเหตุสมผล เนื่องจากถูกแยกออกจากโรงแรม ดังนั้น การเข้าถึงคลาสเหล่านี้ทั้งหมดจึงทำได้ผ่านเอนทิตีรูทเท่านั้น ผ่านทางโรงแรม ในกรณีนี้ อุปกรณ์เป็นเส้นทางที่แตกต่างจากจุดเริ่มต้น เป็นแผนผังที่แตกต่างกันซึ่งมีชุดฟิลด์ต่างกัน

ดังนั้น หากคุณเข้าใจว่าคุณมีเอนทิตีหนึ่งที่เล่นในสองโดเมนที่แตกต่างกัน เพียงแค่ตัดมันออก และมันจะเป็นเพียงการฉายภาพของเอนทิตีหลัก ตัวอย่างเช่น ใน AttachedDevice จะมีช่องที่มีหมายเลขห้อง แต่ในอุปกรณ์ไม่จำเป็นต้องใช้ช่องดังกล่าว

และที่นี่ ตัวอย่างแบบสอบถามว่าจะมีลักษณะอย่างไรในรูปแบบโดเมนดังกล่าว:

  • PUT /hotels/555/rooms/105/attachedDevices - แทนที่ชุดอุปกรณ์ที่เชื่อมต่อทั้งหมดด้วยอุปกรณ์ใหม่
  • POST /hotels/555/rooms/105/attachedDevices - แนบอุปกรณ์อื่น
  • DELETE /hotels/12 - ลบรายละเอียดโรงแรมที่มี ID=12
  • POST /hotels/123/reservations - สร้างการจองใหม่ที่โรงแรม ID=123
CQRS - การแยกความรับผิดชอบในการสืบค้นคำสั่ง

ฉันจะไม่พูดถึงสถาปัตยกรรมนี้ในตอนนี้ แต่ฉันต้องการสรุปสั้นๆ ว่าหลักการทำงานของสถาปัตยกรรมนี้คืออะไร สถาปัตยกรรม CQRS ขึ้นอยู่กับการแยกสตรีมข้อมูล

เรามีหนึ่งเธรดที่ผู้ใช้ส่งคำสั่งไปยังเซิร์ฟเวอร์เพื่อเปลี่ยนโดเมน อย่างไรก็ตาม ไม่ใช่ความจริงที่ว่าการเปลี่ยนแปลงจะเกิดขึ้นจริง เนื่องจากผู้ใช้ไม่ได้จัดการข้อมูลโดยตรง ดังนั้น หลังจากที่ผู้ใช้ส่งคำสั่งเพื่อเปลี่ยนเอนทิตี เซิร์ฟเวอร์จะประมวลผลและใส่ไว้ในโมเดลบางประเภทที่ปรับให้เหมาะสมสำหรับการอ่าน - UI จะอ่าน

แนวทางนี้จะช่วยให้คุณปฏิบัติตามหลักการ REST ได้อย่างง่ายดาย หากมีคำสั่งก็จะมีเอนทิตี "รายการคำสั่ง"

ส่วนที่เหลือโดยไม่ต้องใส่
ในโลก CRUD ที่เรียบง่าย PUT เป็นสิ่งที่เปลี่ยนวัตถุ แต่ถ้าเราปฏิบัติตามหลักการ CQRS อย่างเคร่งครัดและทำทุกอย่างด้วยคำสั่ง PUT จะหายไปเพราะเราไม่สามารถเปลี่ยนวัตถุได้ แต่เราสามารถส่งคำสั่งให้เปลี่ยนวัตถุได้เท่านั้น ในเวลาเดียวกัน คุณสามารถติดตามสถานะการดำเนินการ ยกเลิกคำสั่ง (DELETE) เก็บประวัติการเปลี่ยนแปลงได้อย่างง่ายดาย และผู้ใช้จะไม่เปลี่ยนแปลงอะไรเลย แต่เพียงแค่รายงานความตั้งใจเท่านั้น

กระบวนทัศน์ REST ที่ไม่มี PUT ยังคงเป็นที่ถกเถียงและไม่ได้รับการทดสอบอย่างสมบูรณ์ แต่ในบางกรณีก็สามารถใช้ได้ดีจริงๆ

เนื้อละเอียด VS เนื้อหยาบ
ลองนึกภาพว่าคุณกำลังให้บริการขนาดใหญ่ เป็นวัตถุขนาดใหญ่ ที่นี่คุณมีสองแนวทาง: API แบบละเอียดและ API แบบหยาบ (“Fine-grained” และ “API แบบหยาบ”)

API แบบละเอียด:

  • วัตถุขนาดเล็กจำนวนมาก
  • ตรรกะทางธุรกิจไปที่ฝั่งไคลเอ็นต์
  • คุณจำเป็นต้องรู้ว่าวัตถุเชื่อมต่อกันอย่างไร

API แบบหยาบ:

  • สร้างเอนทิตีเพิ่มเติม
  • การเปลี่ยนแปลงในท้องถิ่นเป็นเรื่องยาก เช่น
    • POST /บล็อก/(id)/ไลค์
  • คุณต้องตรวจสอบสถานะบนไคลเอนต์
  • ไม่สามารถบันทึกวัตถุขนาดใหญ่ได้บางส่วน

ก่อนอื่น ฉันแนะนำให้คุณออกแบบ API แบบละเอียด โดยทุกครั้งที่คุณสร้างอ็อบเจ็กต์ ให้ส่งอ็อบเจ็กต์นั้นไปยังเซิร์ฟเวอร์ สำหรับทุกการกระทำในฝั่งไคลเอ็นต์ จะมีการเรียกไปยังเซิร์ฟเวอร์ อย่างไรก็ตาม การทำงานกับเอนทิตีขนาดเล็กได้ง่ายกว่าการทำงานกับเอนทิตีขนาดใหญ่: หากคุณเขียนเอนทิตีขนาดใหญ่ มันจะยากสำหรับคุณที่จะตัดมันในภายหลัง มันจะเป็นการยากที่จะทำการเปลี่ยนแปลงเล็กน้อยและดึงชิ้นส่วนอิสระออกมา ดังนั้นจึงเป็นการดีกว่าที่จะเริ่มจากหน่วยงานเล็กๆ แล้วค่อยๆ ขยายให้ใหญ่ขึ้น

การกำหนดหมายเลขเวอร์ชัน
มันบังเอิญว่าอุตสาหกรรมของเรามีทัศนคติที่ผ่อนคลายมากต่อสัญญา ด้วยเหตุผลบางประการ ผู้คนเชื่อว่าหากพวกเขาสร้าง API ก็จะกลายเป็น API ของพวกเขาที่พวกเขาสามารถทำทุกอย่างที่พวกเขาต้องการได้ แต่นั่นไม่เป็นความจริง หากคุณเคยเขียน API และมอบให้กับคู่สัญญาอย่างน้อยหนึ่งราย ทุกอย่างจะเป็นเวอร์ชัน 1.0 การเปลี่ยนแปลงใด ๆ ควรส่งผลให้มีการเปลี่ยนเวอร์ชัน เพราะท้ายที่สุดแล้ว ผู้คนจะเชื่อมโยงโค้ดของตนกับเวอร์ชันที่คุณให้ไว้

ในโปรเจ็กต์ล่าสุด เราต้องย้อนกลับ API หลายครั้งเพียงเพราะว่าได้มอบให้กับลูกค้าแล้ว - เราเปลี่ยนรหัสข้อผิดพลาด แต่ลูกค้าก็คุ้นเคยกับรหัสเก่าแล้ว

ตัวเลือกที่ทราบในปัจจุบันสำหรับการกำหนดหมายเลขเวอร์ชันของ Web API คืออะไร

สิ่งที่ง่ายที่สุดคือการระบุเวอร์ชันใน URL

นี่คือตัวเลือกสำเร็จรูปเมื่อคุณไม่จำเป็นต้องทำอะไรด้วยตัวเอง:

นี่คือตัวเลือกสำเร็จรูปตัวหนึ่งที่น่าสนใจ

นี่เป็นเพียงการกำหนดเส้นทางแอตทริบิวต์ที่มีข้อจำกัด หากคุณได้ทำอ็อบเจ็กต์ที่ร้ายแรง คุณอาจได้ทำข้อจำกัดแล้ว ตามหมายเลขเวอร์ชันในแอตทริบิวต์นี้ พวกเขาเพียงแค่ใช้ข้อจำกัด ดังนั้น คุณจึงกำหนดแอ็ตทริบิวต์เดียวกันกับเวอร์ชันที่แตกต่างกัน แต่มีชื่อคอนโทรลเลอร์เดียวกัน ให้กับสองคลาสที่ต่างกัน และระบุเวอร์ชันที่แตกต่างกัน ทุกอย่างทำงานนอกกรอบ...

VersionedRoute("v2/values", เวอร์ชัน = 2)]
config.ConfigureVersioning (
versioningHeaderName: "เวอร์ชัน", vesioningMediaTypes: null);
config.ConfigureVersioning (
versioningHeaderName: null,
vesioningMediaTypes: ใหม่ ("application/vnd.model");

เอกสารประกอบ
มีโอเพ่นซอร์สที่ยอดเยี่ยมซึ่งมีประโยชน์หลายอย่าง - Swagger เราใช้กับอะแดปเตอร์พิเศษ - Swashbuckle
  • http://swagger.io/
  • https://github.com/domaindrivendev/Swashbuckle
หัวเข็มขัด: httpConfiguration .EnableSwagger(c => c.SingleApiVersion("v1", ”Demo API")) .EnableSwaggerUi(); public static void RegisterSwagger(การกำหนดค่า HttpConfiguration นี้) ( config.EnableSwagger(c => ( c.SingleApiVersion("v1 ", "DotNextRZD.PublicAPI") .Description("DotNextRZD Public API") .TermsOfService("ข้อกำหนดและเงื่อนไข") .ติดต่อ(cc => cc .Name("Vyacheslav Mikhaylov") .Url("http://www .dotnextrzd.com") .อีเมล(" [ป้องกันอีเมล]")).License(lc => lc.Name("License").Url("http://tempuri.org/license")); c.IncludeXmlComme nts(GetXmlCommentFile()); c.GroupActionsBy(GetControllerGroupingKey) ; c.OrderActionGroupsBy(c.InjectStylesheet(Assembly.GetExecutingAssembly(), "DotNextRZD.PublicApi .Swagger.) Styles.SwaggerCustom.css"); )); ) )

แท็ก: เพิ่มแท็ก

ในส่วนของอินเทอร์เน็ตภาษารัสเซียมีบทความจำนวนมากเกี่ยวกับบริการเว็บที่ใช้ SOAP และ XML-RPC แต่ด้วยเหตุผลบางประการแทบไม่มีอะไรเลยเกี่ยวกับสถาปัตยกรรม REST ที่ค่อนข้างน่าสังเกต (แต่พบน้อยกว่า)

บทความนี้จะอธิบายพื้นฐานของสถาปัตยกรรม ความสามารถ และตัวอย่างการใช้งาน

ส่วนที่เหลือคืออะไร

REST (การถ่ายโอนสถานะการเป็นตัวแทน) คือรูปแบบของสถาปัตยกรรมซอฟต์แวร์สำหรับระบบแบบกระจาย เช่น เวิลด์ไวด์เว็บ ซึ่งโดยทั่วไปจะใช้ในการสร้างบริการเว็บ คำว่า REST ได้รับการประกาศเกียรติคุณในปี 2000 โดย Roy Fielding หนึ่งในผู้เขียนโปรโตคอล HTTP ระบบที่รองรับ REST เรียกว่าระบบ RESTful

โดยทั่วไป REST เป็นอินเทอร์เฟซการจัดการข้อมูลที่เรียบง่ายโดยไม่ต้องใช้เลเยอร์ภายในเพิ่มเติม ข้อมูลแต่ละชิ้นจะถูกระบุโดยไม่ซ้ำกันด้วยตัวระบุส่วนกลาง เช่น URL แต่ละ URL ก็มีรูปแบบที่กำหนดไว้อย่างเคร่งครัด

และตอนนี้สิ่งเดียวกันก็ชัดเจนยิ่งขึ้น:

การไม่มีเลเยอร์ภายในเพิ่มเติมหมายความว่าข้อมูลจะถูกถ่ายโอนในรูปแบบเดียวกับข้อมูลนั้นเอง เหล่านั้น. เราไม่รวมข้อมูลในรูปแบบ XML เช่น SOAP และ XML-RPC เราไม่ใช้ AMF เช่นเดียวกับ Flash เป็นต้น เราแค่ให้ข้อมูลไปเอง

ข้อมูลแต่ละชิ้นจะถูกระบุโดยไม่ซ้ำกันด้วย URL ซึ่งหมายความว่า URL นั้นเป็นคีย์หลักสำหรับข้อมูลนั้น เหล่านั้น. เช่น หนังสือเล่มที่สามจากชั้นวางหนังสือจะมีลักษณะดังนี้ /book/3 และหน้า 35 ในหนังสือเล่มนี้จะมีลักษณะเช่นนี้ /book/3/page/35 จากที่นี่เราจะได้รูปแบบที่กำหนดไว้อย่างเคร่งครัด ยิ่งไปกว่านั้นไม่สำคัญว่าข้อมูลจะอยู่ในรูปแบบใด /book/3/page/35 - อาจเป็น HTML, สำเนาที่สแกนในรูปแบบไฟล์ jpeg หรือเอกสาร Microsoft Word

วิธีการจัดการข้อมูลบริการจะขึ้นอยู่กับโปรโตคอลการถ่ายโอนข้อมูลทั้งหมด แน่นอนว่าโปรโตคอลที่พบบ่อยที่สุดคือ HTTP ดังนั้นสำหรับ HTTP การดำเนินการกับข้อมูลจะถูกระบุโดยใช้วิธีการ: GET (รับ), PUT (เพิ่ม, แทนที่), POST (เพิ่ม, เปลี่ยนแปลง, ลบ), DELETE (ลบ) ดังนั้นการดำเนินการ CRUD (Create-Read-Updtae-Delete) สามารถทำได้ทั้ง 4 วิธี หรือเฉพาะกับ GET และ POST เท่านั้น

ต่อไปนี้จะมีลักษณะเช่นนี้ในตัวอย่าง:

GET /book/ - รับรายชื่อหนังสือทั้งหมด
GET /book/3/ - รับเล่มที่ 3
PUT /book/ - เพิ่มหนังสือ (ข้อมูลในเนื้อหาคำขอ)

DELETE /book/3 – ลบหนังสือ

ภาคผนวกที่สำคัญ:มีสิ่งที่เรียกว่า REST-Patterns ซึ่งแตกต่างกันในการเชื่อมโยงวิธี HTTP กับสิ่งที่พวกเขาทำ โดยเฉพาะอย่างยิ่ง รูปแบบที่แตกต่างกันจะถือว่า POST และ PUT แตกต่างกัน อย่างไรก็ตาม PUT มีไว้สำหรับการสร้าง เล่นซ้ำ หรืออัปเดต ซึ่งไม่ได้กำหนดไว้สำหรับ POST (การดำเนินการ POST เป็นแบบทั่วไปมากและไม่สามารถแนบความหมายเฉพาะเข้าไปได้)- ดังนั้นตัวอย่างของฉันจะถูกต้องทั้งในรูปแบบนี้และในรูปแบบนี้หากสลับ POST และ PUT

โดยทั่วไป POST สามารถใช้กับการเปลี่ยนแปลงทั้งหมดพร้อมกันได้:
POST /book/ – เพิ่มหนังสือ (ข้อมูลในส่วนเนื้อหาคำขอ)
POST /book/3 – เปลี่ยนหนังสือ (ข้อมูลในเนื้อหาคำขอ)
POST /book/3 – ลบหนังสือ (เนื้อหาคำขอว่างเปล่า)

ซึ่งบางครั้งจะช่วยให้คุณสามารถหลีกเลี่ยงปัญหาอันไม่พึงประสงค์ที่เกี่ยวข้องกับการปฏิเสธ PUT และ DELETE ได้

การใช้ REST เพื่อสร้างบริการบนเว็บ

ดังที่คุณทราบ บริการเว็บเป็นแอปพลิเคชันที่ทำงานบนเวิลด์ไวด์เว็บและเข้าถึงได้ผ่านโปรโตคอล HTTP และมีการแลกเปลี่ยนข้อมูลโดยใช้รูปแบบ XML ดังนั้นรูปแบบข้อมูลที่ส่งในเนื้อหาคำขอจะเป็น XML เสมอ

สำหรับแต่ละหน่วยข้อมูล (ข้อมูล) จะมีการกำหนดการดำเนินการ 5 รายการ กล่าวคือ:

รับข้อมูล/ (ดัชนี)– รับรายการวัตถุทั้งหมด ตามกฎแล้ว นี่คือรายการแบบง่าย เช่น มีเพียงตัวระบุออบเจ็กต์และฟิลด์ชื่อ โดยไม่มีข้อมูลอื่น

รับ /ข้อมูล/(id) (ดู)– รับข้อมูลที่สมบูรณ์เกี่ยวกับวัตถุ

ใส่ /ข้อมูล/หรือ โพสต์ /ข้อมูล/ (สร้าง)– สร้างวัตถุใหม่ ข้อมูลจะถูกส่งไปในส่วนเนื้อหาของคำขอโดยไม่ต้องใช้การเข้ารหัส แม้แต่ urlencode ใน PHP สามารถรับเนื้อหาคำขอได้ด้วยวิธีนี้:

ฟังก์ชัน getBody() (
ถ้า (!isset($HTTP_RAW_POST_DATA))
$HTTP_RAW_POST_DATA = file_get_contents("php://input");
ส่งคืน $HTTP_RAW_POST_DATA;
}

โพสต์ /ข้อมูล/(id)หรือ ใส่ /ข้อมูล/(id) (แก้ไข)– เปลี่ยนแปลงข้อมูลด้วยตัวระบุ (id) ซึ่งอาจแทนที่ข้อมูลเหล่านั้นได้ ข้อมูลจะถูกส่งไปในส่วนของคำขอด้วย แต่มีความแตกต่างกันเล็กน้อยในที่นี้ต่างจาก PUT ความจริงก็คือคำขอ POST หมายถึงการมีอยู่ของ urldecoded-post-data เหล่านั้น. หากคุณไม่ใช้การเข้ารหัส ถือเป็นการละเมิดมาตรฐาน ใครก็ตามที่ต้องการมัน - บางคนไม่ใส่ใจกับมาตรฐาน บางคนใช้ตัวแปรหลังบางอย่าง

ลบ /ข้อมูล/(id) (ลบ)– ลบข้อมูลด้วยตัวระบุ (id)

ฉันขอทราบอีกครั้งว่าในตัวอย่างของเรา /info/ - อาจขึ้นอยู่กับข้อมูลอื่น ๆ ซึ่งสามารถ (และควร) สะท้อนให้เห็นใน URL:

/data/4/otherdata/6/info/3/ …และสิ่งที่คล้ายกัน

จะได้ข้อสรุปอะไรจากสิ่งนี้:

อย่างที่คุณเห็น สถาปัตยกรรม REST นั้นใช้งานง่ายมาก ตามประเภทของคำขอที่มาถึง คุณสามารถระบุได้ทันทีว่าคำขอนั้นทำอะไรโดยไม่ต้องเข้าใจรูปแบบ (ต่างจาก SOAP, XML-RPC) ข้อมูลจะถูกถ่ายโอนโดยไม่ต้องใช้เลเยอร์เพิ่มเติม ดังนั้น REST จึงถือว่าใช้ทรัพยากรน้อยกว่า เนื่องจากคุณไม่จำเป็นต้องแยกวิเคราะห์คำขอเพื่อทำความเข้าใจว่าควรทำอย่างไร และคุณไม่จำเป็นต้องแปลข้อมูลจากรูปแบบหนึ่งเป็นอีกรูปแบบหนึ่ง

การใช้งานจริง.

ข้อได้เปรียบที่สำคัญที่สุดของบริการนี้คือระบบต่างๆ สามารถทำงานร่วมกับบริการเหล่านี้ได้ ไม่ว่าจะเป็นเว็บไซต์ แฟลช โปรแกรม ฯลฯ เนื่องจากวิธีการแยกวิเคราะห์ XML และการดำเนินการคำขอ HTTP มีอยู่ในเกือบทุกที่

สถาปัตยกรรม REST ช่วยให้งานนี้ง่ายขึ้นอย่างมาก แน่นอนว่าในความเป็นจริง สิ่งที่อธิบายไว้นั้นไม่เพียงพอ เนื่องจากคุณไม่สามารถให้โอกาสใครในการเปลี่ยนแปลงข้อมูลได้ นั่นก็คือการอนุญาตและการรับรองความถูกต้องก็เป็นสิ่งจำเป็นเช่นกัน แต่สามารถแก้ไขได้ง่ายๆ โดยใช้เซสชันประเภทต่างๆ หรือเพียงแค่การตรวจสอบสิทธิ์ HTTP

สวัสดีผู้อ่านที่รัก! ก่อนที่คุณจะเริ่มอ่านบทความนี้ ฉันอยากจะอธิบายจุดประสงค์ของการสร้างบทความนี้และบอกคุณว่าอะไรกระตุ้นให้ฉันเขียนบทความนี้

ในระหว่างโครงการหนึ่งของบริษัทเรา จำเป็นต้องออกแบบแอปพลิเคชันเซิร์ฟเวอร์ในรูปแบบ REST ในตอนแรก ดูเหมือนว่านี่เป็นงานที่ค่อนข้างง่ายและประสบการณ์ของเราเองเท่านั้นที่จะแก้ปัญหาได้

แต่เมื่อกระบวนการพัฒนาสถาปัตยกรรมและการนำบริการ REST ไปสู่รูปแบบเดียวเริ่มต้นขึ้น เพื่อนร่วมงานของฉันและฉันเริ่มมีปัญหาที่ขัดแย้งและมุมมองที่แตกต่างกันเกี่ยวกับการดำเนินการด้านนี้หรือด้านนั้น จากนั้นเราก็ตระหนักว่าเราจำเป็นต้องเปิด Google และขอความช่วยเหลือจากภูมิปัญญาโดยรวม ศึกษาแนวทางปฏิบัติที่ดีที่สุดที่นำเสนอซึ่งควรใช้เมื่อออกแบบแอปพลิเคชัน RESTful

บทความนี้จะมีประโยชน์สำหรับผู้ที่มีประสบการณ์กับเว็บแอปพลิเคชันมาบ้างแล้ว (และอาจรวมถึงบริการ REST) ​​แต่จำเป็นต้องรวบรวมและสร้างมาตรฐานความรู้ที่ได้รับ

คำนิยาม

ก่อนอื่นคุณต้องตัดสินใจว่า REST คืออะไร Wikipedia ให้คำตอบต่อไปนี้สำหรับคำถามนี้ พักผ่อน (การโอนตัวแทนของรัฐ- "การถ่ายโอนสถานะการนำเสนอ") เป็นรูปแบบสถาปัตยกรรมของการโต้ตอบระหว่างส่วนประกอบของแอปพลิเคชันแบบกระจายบนเครือข่าย REST คือชุดข้อจำกัดที่สอดคล้องกันซึ่งพิจารณาเมื่อออกแบบระบบไฮเปอร์มีเดียแบบกระจาย

ในคำพูดของฉันเอง ฉันจะอธิบายแนวคิดของ REST ว่าเป็น “ชุดคำแนะนำที่ช่วยให้คุณสามารถรวมการโต้ตอบของแอปพลิเคชันไคลเอนต์และเซิร์ฟเวอร์เข้าด้วยกัน”
ในบทความนี้ ฉันจะพยายามพูดถึง "คำแนะนำ" เหล่านี้ซึ่งจะช่วยให้คุณออกแบบและสร้างบริการ REST ตามแนวทางปฏิบัติที่เป็นที่ยอมรับโดยทั่วไป

คุณต้องเข้าใจว่าบริการ REST คืออะไร ฉันจะกำหนดบริการ REST ว่าเป็น "จุดโต้ตอบระหว่างแอปพลิเคชันไคลเอนต์และเซิร์ฟเวอร์" ในคำศัพท์เฉพาะของ Java นี่คือเซิร์ฟเล็ตที่ไคลเอ็นต์ส่งคำขอไป

ปัญหา

แต่ก่อนที่ฉันจะเริ่มต้นอธิบายกฎ ฉันอยากจะถ่ายทอดแนวคิดที่ว่า REST ไม่ใช่มาตรฐาน ดังนั้นจึงไม่มีกฎที่เข้มงวดเพียงข้อเดียวที่ควรปฏิบัติตาม ซึ่งหมายความว่ายังไม่มีข้อตกลงที่สมบูรณ์ว่าโซลูชันใดเหมาะที่สุดที่จะใช้ในสถานการณ์ที่กำหนด บ่อยครั้งที่มีการถกเถียงกันเกี่ยวกับวิธีการใช้ HTTP ใดและโค้ด HTTP ใดที่จะส่งคืนในแต่ละสถานการณ์เฉพาะ

ชื่อบริการ

ขั้นแรก คุณต้องเลือกชื่อสำหรับบริการ REST ตามชื่อบริการ ฉันหมายถึงเส้นทางใน URI คำขอ ตัวอย่างเช่น, http://my-site.by/api/rest/service/name- ในการเลือกชื่อ เราต้องเข้าใจว่า "ทรัพยากร" คืออะไรในสถาปัตยกรรม REST

มุมมองทรัพยากร

ในคำศัพท์ REST สิ่งใดก็ตามสามารถเป็นทรัพยากรได้ - เอกสาร HTML รูปภาพ ข้อมูลเกี่ยวกับผู้ใช้เฉพาะ ฯลฯ หากทรัพยากรเป็นออบเจ็กต์บางประเภท เป็นเรื่องง่ายที่จะแสดงโดยใช้รูปแบบมาตรฐานบางรูปแบบ เช่น XML หรือ JSON จากนั้นเซิร์ฟเวอร์สามารถส่งทรัพยากรนี้โดยใช้รูปแบบที่เลือก และไคลเอนต์สามารถทำงานกับทรัพยากรที่ได้รับจากเซิร์ฟเวอร์โดยใช้รูปแบบเดียวกัน

ตัวอย่างการแสดงทรัพยากร "โปรไฟล์" ในรูปแบบ JSON:

    "รหัส" :1 ,

    "ชื่อ" :"มาเฮช" ,

    "เข้าสู่ระบบ" :"มเนศ"

REST ไม่ได้วางข้อจำกัดที่ชัดเจนเกี่ยวกับรูปแบบที่ต้องใช้เพื่อแสดงทรัพยากร แต่มีกฎหลายข้อที่ต้องปฏิบัติตามเมื่อออกแบบรูปแบบที่จะใช้เพื่อแสดงทรัพยากร:

  • ลูกค้าและเซิร์ฟเวอร์จะต้อง "เข้าใจ" และสามารถทำงานกับรูปแบบที่เลือกได้
  • สามารถอธิบายทรัพยากรได้อย่างสมบูรณ์โดยใช้รูปแบบที่เลือก โดยไม่คำนึงถึงความซับซ้อนของทรัพยากร
  • รูปแบบควรจัดให้มีความสามารถในการแสดงความสัมพันธ์ระหว่างทรัพยากร

ตัวอย่างการแสดงทรัพยากร "คำสั่งซื้อ" และการเชื่อมต่อกับทรัพยากร "โปรไฟล์":

    รหัส: 11254,

    สกุลเงิน: "EUR" ,

    จำนวน: 100

    ประวัติโดยย่อ: (

    รหัส: 11,

    ยูริ: "http://MyService/Profiles/11"

อย่างที่คุณเห็น ไม่จำเป็นต้องทำซ้ำโครงสร้างทั้งหมดของทรัพยากรที่อ้างอิงโดยทรัพยากรอื่นทั้งหมด คุณสามารถใช้ลิงก์ที่ชัดเจนไปยังแหล่งข้อมูลอื่นแทนได้

การเข้าถึงทรัพยากร

ทรัพยากรแต่ละรายการต้องได้รับการระบุโดยไม่ซ้ำกันด้วยตัวระบุถาวร "ถาวร" หมายความว่าตัวระบุจะไม่เปลี่ยนแปลงในระหว่างการสื่อสาร และแม้ว่าสถานะของทรัพยากรจะเปลี่ยนแปลงก็ตาม หากทรัพยากรได้รับการกำหนดตัวระบุอื่น เซิร์ฟเวอร์จะต้องแจ้งให้ลูกค้าทราบว่าคำขอไม่สำเร็จและจัดเตรียมลิงก์ไปยังที่อยู่ใหม่ ทรัพยากรแต่ละรายการจะถูกระบุโดยไม่ซ้ำกันด้วย URL ซึ่งหมายความว่า URL นั้นเป็นคีย์หลักสำหรับรายการข้อมูล นั่นคือหนังสือเล่มที่สองจากชั้นหนังสือจะมีลักษณะเช่นนี้ /หนังสือ/2 และ 41 หน้าในหนังสือเล่มนี้ - /หนังสือ/2/หน้า/41 - จากที่นี่เราจะได้รูปแบบที่กำหนดไว้อย่างเคร่งครัด ยิ่งกว่านั้นไม่สำคัญเลยว่าข้อมูลจะอยู่ในรูปแบบใด /หนังสือ/2/หน้า/41 – อาจเป็น HTML, สำเนาที่สแกนในรูปแบบไฟล์ jpeg หรือเอกสาร Word

ขอแนะนำให้ใช้ชื่อทรัพยากรพหูพจน์เมื่อกำหนดชื่อเซอร์วิส REST วิธีการนี้อนุญาตให้คุณเพิ่มเซอร์วิส REST ใหม่โดยการขยายชื่อของบริการที่มีอยู่เท่านั้น ตัวอย่างเช่นการบริการ /หนังสือ จะส่งรายชื่อหนังสือทั้งหมดกลับมาให้เรา /หนังสือ/3 จะกลับมาข้อมูลเกี่ยวกับหนังสือเล่มที่ 3 และบริการ /books/3/pages จะกลับมาทุกหน้าของหนังสือเล่มที่ 3

สำหรับบริการที่ดำเนินการบางอย่างกับทรัพยากร มี 2 วิธีในการระบุการดำเนินการ: ในชื่อบริการหรือในพารามิเตอร์ ตัวอย่างเช่น, /books/3/clean หรือ /books/3?clean - ฉันชอบตัวเลือกแรกเนื่องจากโดยปกติแล้วบริการดังกล่าวมักจะใช้วิธีการ POST ที่ไม่รองรับการส่งพารามิเตอร์ไปยัง URl ซึ่งทำให้บริการตามความคิดของฉันไม่สามารถอ่านได้มากนัก ด้วยการกำหนดประเภทการดำเนินการในชื่อบริการ เราทำให้บริการของเราขยายได้มากขึ้น เนื่องจากไม่ได้ขึ้นอยู่กับประเภทวิธี HTTP

ไม่แนะนำให้ใช้ชื่อที่ประกอบด้วยคำหลายคำและอธิบายองค์ประกอบทางธุรกิจของบริการ (ตามที่แนะนำเมื่อตั้งชื่อวิธี Java) ตัวอย่างเช่นแทนที่จะเป็น /getAllCars ควรทำวิธีจะดีกว่า /รถ - ถ้าวิธีการนี้ไม่สามารถอธิบายได้ด้วยวิธีใดวิธีหนึ่งด้วยคำเดียว ก็จำเป็นต้องใช้รูปแบบตัวคั่นเพียงรูปแบบเดียว ฉันมักจะใช้ "-" ซึ่งเป็นแนวทางที่ได้รับความนิยมมากที่สุด ตัวอย่างเช่น, /cars/3/ขายได้.

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการออกแบบชื่อบริการ REST ได้ใน

วิธีการ HTTP

REST ใช้วิธี HTTP หลัก 4 วิธี: GET, POST, PUT, DELETE ในกรณีส่วนใหญ่ แต่ละวิธีใช้เพื่อดำเนินการที่กำหนดไว้ล่วงหน้าจาก CRUD ( ทำซ้ำ, อี๊ด, ยูวันที่, elete - "สร้าง อ่าน อัปเดต ลบ").
POST - สร้าง, GET - อ่าน, PUT - อัปเดต, ลบ - ลบ

ภาคผนวกที่สำคัญ: มีสิ่งที่เรียกว่า REST-Patterns ซึ่งแตกต่างกันในการเชื่อมโยงวิธี HTTP กับสิ่งที่พวกเขาทำ โดยเฉพาะอย่างยิ่ง รูปแบบที่แตกต่างกันจะถือว่า POST และ PUT แตกต่างกัน อย่างไรก็ตาม PUT มีวัตถุประสงค์เพื่อสร้าง แทนที่ หรืออัปเดต สำหรับ POST สิ่งนี้ไม่ได้ถูกกำหนดไว้ (การดำเนินการ POST เป็นแบบทั่วไปมากและไม่สามารถแนบความหมายเฉพาะลงไปได้) ดังนั้นบางครั้ง POST และ PUT สามารถสลับกันได้ แต่ในกรณีส่วนใหญ่ POST ใช้สำหรับการสร้าง และ PUT ใช้สำหรับการแก้ไข และฉันจะอธิบายในภายหลังว่าทำไม

ฉันจะยกตัวอย่างการใช้วิธีต่างๆ เพื่อโต้ตอบกับทรัพยากร

  • รับ /หนังสือ/– รับรายชื่อหนังสือทั้งหมด ตามกฎแล้ว นี่คือรายการแบบง่าย เช่น มีเพียงฟิลด์ตัวระบุและชื่อออบเจ็กต์ โดยไม่มีข้อมูลอื่น
  • GET /หนังสือ/(id)– ได้รับข้อมูลครบถ้วนเกี่ยวกับหนังสือ
  • โพสต์ /หนังสือ/– สร้างหนังสือเล่มใหม่ ข้อมูลจะถูกส่งไปในเนื้อความของคำขอ
    PUT /หนังสือ/(id)– เปลี่ยนแปลงข้อมูลเกี่ยวกับหนังสือด้วยตัวระบุ (id) ซึ่งอาจแทนที่ข้อมูลเหล่านั้น ข้อมูลจะถูกส่งไปในเนื้อหาของคำขอด้วย
  • ตัวเลือก /หนังสือ– รับรายการการดำเนินการที่รองรับสำหรับทรัพยากรที่ระบุ (ไม่ได้ใช้งานจริง)
  • ลบ /หนังสือ/(id)– ลบข้อมูลด้วยตัวระบุ (id)

ความปลอดภัยและความเป็นอมตะ

ความรู้เกี่ยวกับความปลอดภัยและความสม่ำเสมอของวิธีการเหล่านี้จะช่วยในการเลือกวิธี HTTP ได้อย่างมาก

คำขอที่ปลอดภัยคือคำขอที่ไม่เปลี่ยนสถานะของแอปพลิเคชัน

แบบสอบถาม idempotent คือแบบสอบถามที่มีผลเมื่อดำเนินการหลายครั้งจะเท่ากับผลเมื่อดำเนินการเพียงครั้งเดียว

เมื่อพิจารณาจากตารางนี้ คำขอ GET ไม่ควรเปลี่ยนสถานะของทรัพยากรที่จะนำไปใช้ คำขอ PUT และ DELETE สามารถเปลี่ยนสถานะของทรัพยากรได้ แต่สามารถทำซ้ำได้อย่างปลอดภัย หากคุณไม่แน่ใจว่าคำขอก่อนหน้านี้เสร็จสมบูรณ์แล้ว โดยหลักการแล้ว นี่เป็นตรรกะ: หากคุณทำซ้ำคำขอซ้ำ ๆ เพื่อลบหรือแทนที่ทรัพยากรเฉพาะ ผลลัพธ์จะเป็นการลบหรือแทนที่ทรัพยากร แต่คำขอ POST ตามที่เราเห็นจากตารางนั้นไม่ปลอดภัยและไม่ใช่ตัวเปลี่ยนตำแหน่ง นั่นคือไม่เพียงแต่จะเปลี่ยนสถานะของทรัพยากรเท่านั้น แต่การทำซ้ำซ้ำ ๆ จะสร้างผลกระทบขึ้นอยู่กับจำนวนการทำซ้ำ ความหมายของมันสอดคล้องกับการดำเนินการเพิ่มองค์ประกอบใหม่ลงในฐานข้อมูล: แบบสอบถามถูกดำเนินการ X ครั้งและมีการเพิ่มองค์ประกอบ X ลงในฐานข้อมูล

ฉันจะยกตัวอย่างด้วยว่าเหตุใดคำขอ GET จึงไม่ควรเปลี่ยนสถานะของทรัพยากร คำขอ GET สามารถแคชได้ ตัวอย่างเช่น ที่ระดับพร็อกซีเซิร์ฟเวอร์ ในกรณีนี้ คำขออาจไม่ถึงแม้แต่เซิร์ฟเวอร์แอปพลิเคชัน และพร็อกซีเซิร์ฟเวอร์จะส่งคืนข้อมูลจากแคชเป็นการตอบกลับ

รหัส HTTP

มาตรฐาน HTTP อธิบายรหัสสถานะมากกว่า 70 รหัส ถือเป็นแนวปฏิบัติที่ดีที่จะใช้อย่างน้อยแบบพื้นฐาน

  • 200 – ตกลง – คำขอสำเร็จ หากลูกค้าร้องขอข้อมูลใดๆ ข้อมูลนั้นจะอยู่ในส่วนหัวและ/หรือเนื้อหาของข้อความ
  • 201 – ตกลง – เนื่องจากการดำเนินการตามคำขอสำเร็จ ทรัพยากรใหม่จึงถูกสร้างขึ้น
  • 204 – ตกลง – ลบทรัพยากรสำเร็จแล้ว
  • 304 – ไม่ดัดแปลง – ไคลเอนต์สามารถใช้ข้อมูลจากแคชได้
  • 400 – คำขอไม่ถูกต้อง – คำขอไม่ถูกต้องหรือไม่สามารถดำเนินการได้
  • 401 – ไม่ได้รับอนุญาต – คำขอต้องมีการตรวจสอบสิทธิ์ผู้ใช้
  • 403 – ถูกห้าม – เซิร์ฟเวอร์เข้าใจคำขอแล้ว แต่ปฏิเสธที่จะดำเนินการหรือการเข้าถึงถูกปฏิเสธ
  • 404 – ไม่พบ – ไม่พบทรัพยากร
  • 500 – ข้อผิดพลาดเซิร์ฟเวอร์ภายใน – นักพัฒนา API ควรพยายามหลีกเลี่ยงข้อผิดพลาดดังกล่าว

ข้อผิดพลาดเหล่านี้ควรถูกจับได้ในบล็อก catch ส่วนกลางที่บันทึกไว้ แต่ไม่ควรส่งคืนในการตอบกลับ

ยิ่งเราใช้ชุดโค้ดที่กว้างขวางมากขึ้น API ที่เราสร้างก็จะยิ่งเข้าใจได้มากขึ้นเท่านั้น อย่างไรก็ตาม คุณต้องคำนึงว่าเบราว์เซอร์ประมวลผลโค้ดบางอย่างแตกต่างออกไป ตัวอย่างเช่น เบราว์เซอร์บางตัวที่ได้รับรหัสตอบกลับ 307 จะทำการเปลี่ยนเส้นทางทันที ในขณะที่เบราว์เซอร์บางตัวอนุญาตให้คุณจัดการกับสถานการณ์นี้และยกเลิกการดำเนินการได้ ก่อนที่คุณจะใช้โค้ดใดๆ คุณต้องเข้าใจอย่างถ่องแท้ว่าโค้ดจะถูกประมวลผลบนฝั่งไคลเอ็นต์อย่างไร!

ส่วนหัว

  • ชนิดของเนื้อหา- รูปแบบคำขอ;
  • ยอมรับ- รายการรูปแบบการตอบกลับ

ตัวเลือกการค้นหาทรัพยากร

เพื่อให้ใช้บริการที่รับผิดชอบในการส่งคืนข้อมูลใด ๆ ได้ง่ายขึ้น และนอกจากจะทำให้มีประสิทธิผลมากขึ้นแล้ว ยังจำเป็นต้องใช้พารามิเตอร์สำหรับการเรียงลำดับ การกรอง การเลือกฟิลด์ และการแบ่งหน้าเป็นพารามิเตอร์แบบสอบถาม

การกรอง

ใช้พารามิเตอร์การค้นหาที่ไม่ซ้ำกันสำหรับแต่ละฟิลด์เพื่อใช้การกรอง วิธีนี้จะจำกัดจำนวนข้อมูลที่แสดง ซึ่งจะปรับเวลาการประมวลผลคำขอให้เหมาะสมที่สุด

ตัวอย่างเช่น หากต้องการแสดง Red Book ทั้งหมด คุณต้องเรียกใช้แบบสอบถามต่อไปนี้:

GET /books?color=red

การเรียงลำดับ

การเรียงลำดับจะดำเนินการคล้ายกับการกรอง ตัวอย่างเช่น หากต้องการแสดงหนังสือทั้งหมดโดยเรียงลำดับตามปีที่พิมพ์จากมากไปน้อยและตามชื่อเรื่องจากน้อยไปมาก คุณต้องเรียกใช้แบบสอบถามต่อไปนี้:

GET /books?sort=-ปี,+ชื่อ

การแบ่งหน้า

เพื่อรองรับความสามารถในการโหลดรายการทรัพยากรที่ควรแสดงบนหน้าแอปพลิเคชันเฉพาะ REST API ต้องมีฟังก์ชันการแบ่งหน้า มันถูกนำไปใช้โดยใช้พารามิเตอร์ขีดจำกัดและออฟเซ็ตที่เราคุ้นเคยจาก SQL ตัวอย่างเช่น:

GET /books?offset=10&limit=5

นอกจากนี้ แนวทางปฏิบัติที่ดีในการแสดงลิงก์ไปยังหน้าก่อนหน้า ถัดไป หน้าแรก และหน้าสุดท้ายในส่วนหัวของลิงก์ ตัวอย่างเช่น:

ลิงค์: - rel = "ถัดไป",
- rel="สุดท้าย",
- rel="ครั้งแรก",
- rel="ก่อนหน้า"

การเลือกฟิลด์ทรัพยากร

เพื่อการใช้บริการที่สะดวกยิ่งขึ้น เพื่อประหยัดการรับส่งข้อมูล คุณสามารถให้ความสามารถในการควบคุมรูปแบบเอาต์พุตข้อมูล มีการนำไปใช้โดยการจัดเตรียมความสามารถในการเลือกฟิลด์ทรัพยากรที่บริการ REST ควรส่งคืน ตัวอย่างเช่น หากคุณต้องการรับเฉพาะรหัสหนังสือและสีหนังสือ คุณต้องเรียกใช้แบบสอบถามต่อไปนี้:

GET /books?fields=id,color

การจัดเก็บของรัฐ

ข้อจำกัดประการหนึ่งของบริการ RESTful คือ ไม่จำเป็นต้องจัดเก็บสถานะของไคลเอ็นต์ที่พวกเขารับคำขอ

ตัวอย่างของบริการไร้สัญชาติ:
คำขอ1:
คำขอ2: รับ http://MyService/Persons/2 HTTP/1.1

แต่ละคำขอเหล่านี้สามารถดำเนินการได้โดยแยกจากกัน

ตัวอย่างของบริการที่จัดเก็บสถานะ:
คำขอ1: รับ http://MyService/Persons/1 HTTP/1.1
คำขอ2: รับ http://MyService/NextPerson HTTP/1.1

ในการประมวลผลคำขอที่สอง เซิร์ฟเวอร์จะต้อง "จดจำ" รหัสของบุคคลสุดท้ายที่ลูกค้าร้องขอ เหล่านั้น. เซิร์ฟเวอร์จะต้อง "จดจำ" สถานะปัจจุบัน มิฉะนั้นจะไม่สามารถประมวลผลคำขอที่สองได้ เมื่อออกแบบบริการ คุณควรหลีกเลี่ยงความจำเป็นในการจัดเก็บสถานะ เนื่องจากมีข้อดีหลายประการ

ประโยชน์ของบริการไร้สัญชาติ:

  • การบริการดำเนินการตามคำขออย่างเป็นอิสระจากกัน
  • สถาปัตยกรรมการบริการนั้นง่ายขึ้น
  • ไม่จำเป็นต้องใช้ความพยายามเพิ่มเติมในการใช้บริการโดยใช้โปรโตคอล HTTP ซึ่งก็ไร้สัญชาติเช่นกัน

ข้อเสียของบริการไร้สัญชาติ:

  • ลูกค้าเองจะต้องรับผิดชอบในการส่งต่อบริบทที่จำเป็นไปยังบริการ

การกำหนดเวอร์ชัน

แนวปฏิบัติที่ดีในการสนับสนุนการกำหนดเวอร์ชันของ REST API สิ่งนี้จะช่วยให้คุณสามารถขยาย API ได้อย่างง่ายดายในอนาคต โดยไม่จำเป็นต้องทำการเปลี่ยนแปลงกับไคลเอนต์ที่ใช้งานอยู่แล้ว
มีหลายวิธีในการดำเนินการกำหนดเวอร์ชัน:

  • การใช้ส่วนหัวยอมรับ ในกรณีนี้ เวอร์ชัน API จะแสดงอยู่ใน Accept - ยอมรับ:ข้อความ/v2+json
  • การใช้ URI ในแนวทางนี้ เวอร์ชัน API จะถูกระบุโดยตรงใน URI - http://localhost/api/v2/books
  • การใช้ส่วนหัวที่กำหนดเอง คุณสามารถใช้ส่วนหัวของคุณเองได้ ซึ่งจะรับผิดชอบในการส่งเวอร์ชัน API เท่านั้น - API เวอร์ชัน:v2
  • การใช้พารามิเตอร์แบบสอบถาม คุณสามารถใช้พารามิเตอร์การสืบค้นเพื่อส่งเวอร์ชัน API - /หนังสือ?v=2

แต่ละวิธีที่นำเสนอมีสิทธิ์ที่จะมีอยู่ แต่ละวิธีมีข้อดีและข้อเสียของตัวเอง อย่างไรก็ตาม ขึ้นอยู่กับคุณที่จะตัดสินใจว่าวิธีใดในการนำการกำหนดเวอร์ชันไปใช้ที่เหมาะกับโปรเจ็กต์ของคุณ

เอกสารประกอบ

เพื่อความสะดวกในการใช้บริการ REST ของเรา คุณต้องสร้างเอกสารที่ดีและเข้าใจได้ คุณสามารถใช้เครื่องมือต่างๆ เพื่อวัตถุประสงค์เหล่านี้ได้ เช่น Mashape หรือ Apiary แต่ฉันแนะนำให้ใช้ Swagger

Swagger เป็นเทคโนโลยีที่ช่วยให้คุณสามารถบันทึกบริการ REST ได้ Swagger รองรับภาษาและเฟรมเวิร์กการเขียนโปรแกรมมากมาย นอกจากนี้ Swagger ยังมี UI สำหรับการดูเอกสาร

คุณสามารถรับข้อมูลรายละเอียดเพิ่มเติมเกี่ยวกับ Swagger ได้ที่นี่

การเก็บถาวร

เก็บเอาไว้

นอกจากนี้ เพื่อลดการสืบค้นไปยังฐานข้อมูลและเพิ่มประสิทธิภาพของบริการ REST ของเรา ขอแนะนำให้ใช้กลไกการแคช การแคชสามารถกำหนดค่าได้ทั้งในระดับเซิร์ฟเวอร์และในแอปพลิเคชันนั้นขึ้นอยู่กับสถานการณ์

การแคชสามารถควบคุมได้โดยใช้ส่วนหัว HTTP ต่อไปนี้:

  • วันที่ - วันที่และเวลาที่สร้างทรัพยากร
  • แก้ไขล่าสุด - วันที่และเวลาของการแก้ไขทรัพยากรครั้งล่าสุดบนเซิร์ฟเวอร์
  • Cache-Control - ส่วนหัว HTTP 1.1 ใช้เพื่อควบคุมการแคช
  • อายุ - เวลาที่ผ่านไปนับตั้งแต่ได้รับทรัพยากรครั้งล่าสุด สามารถเพิ่มส่วนหัวได้โดยส่วนประกอบระดับกลาง (ระหว่างไคลเอนต์และเซิร์ฟเวอร์) (เช่น พร็อกซีเซิร์ฟเวอร์)

โพสต์นี้เป็นคำตอบสำหรับคำถามที่ถามในความคิดเห็นต่อหนึ่งในบทความของฉัน

ในบทความนี้ ฉันอยากจะบอกคุณว่าวิธี HTTP GET/POST/PUT/DELETE คืออะไร และวิธีอื่นๆ คืออะไร เหตุใดจึงคิดค้นวิธีเหล่านี้ขึ้นมา และใช้งานอย่างไรตาม REST

HTTP

ดังนั้นหนึ่งในโปรโตคอลหลักของอินเทอร์เน็ตคืออะไร? ฉันจะส่งคนอวดรู้ไปที่ RFC2616 แล้วฉันจะบอกส่วนที่เหลืออย่างมนุษย์ปุถุชน :)

โปรโตคอลนี้อธิบายปฏิสัมพันธ์ระหว่างคอมพิวเตอร์สองเครื่อง (ไคลเอนต์และเซิร์ฟเวอร์) ที่สร้างขึ้นบนพื้นฐานของข้อความที่เรียกว่าคำขอ (คำขอ) และการตอบสนอง (การตอบสนอง) แต่ละข้อความประกอบด้วยสามส่วน: บรรทัดเริ่มต้น ส่วนหัว และเนื้อหา ในกรณีนี้ ต้องใช้เฉพาะเส้นเริ่มต้นเท่านั้น

บรรทัดเริ่มต้นสำหรับคำขอและการตอบกลับมีรูปแบบที่แตกต่างกัน - เราสนใจเฉพาะบรรทัดเริ่มต้นของคำขอเท่านั้น ซึ่งมีลักษณะดังนี้:

URI วิธีการ HTTP/ รุ่น ,

โดยที่ METHOD คือวิธีการร้องขอ HTTP, URI คือตัวระบุทรัพยากร, VERSION คือเวอร์ชันโปรโตคอล (ปัจจุบันคือเวอร์ชัน 1.1)

ส่วนหัวคือชุดของคู่ชื่อ-ค่าที่คั่นด้วยเครื่องหมายทวิภาค ส่วนหัวถ่ายทอดข้อมูลบริการต่างๆ: การเข้ารหัสข้อความ ชื่อและเวอร์ชันของเบราว์เซอร์ ที่อยู่ที่ลูกค้ามา (ผู้อ้างอิง) และอื่นๆ

เนื้อความของข้อความคือข้อมูลจริงที่ถูกส่ง ในการตอบกลับ ตามกฎแล้วข้อมูลที่ส่งคือหน้า HTML ที่เบราว์เซอร์ร้องขอ และในคำขอ เช่น ในเนื้อหาของข้อความ เนื้อหาของไฟล์ที่อัปโหลดไปยังเซิร์ฟเวอร์จะถูกส่ง แต่ตามกฎแล้ว จะไม่มีเนื้อหาข้อความในคำขอเลย

ตัวอย่างการโต้ตอบ HTTP

ลองดูตัวอย่าง

ขอ:
GET /index.php HTTP/1.1 โฮสต์: example.com ตัวแทนผู้ใช้: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5 ยอมรับ: ข้อความ/html การเชื่อมต่อ: ปิด
บรรทัดแรกคือบรรทัดแบบสอบถาม ส่วนที่เหลือเป็นส่วนหัว เนื้อหาข้อความหายไป

คำตอบ:
HTTP/1.0 200 ตกลง เซิร์ฟเวอร์: nginx/0.6.31 ภาษาเนื้อหา: ru ประเภทเนื้อหา: ข้อความ/html; charset=utf-8 Content-Length: 1234 Connection: close ... หน้า HTML เอง...

ทรัพยากรและวิธีการ

กลับไปที่บรรทัดเริ่มต้นของคำขอและจำไว้ว่าคำขอนั้นมีพารามิเตอร์เช่น URI ซึ่งย่อมาจาก Uniform Resource Identifier - ตัวระบุทรัพยากรแบบเดียวกัน ตามกฎแล้วทรัพยากรคือไฟล์บนเซิร์ฟเวอร์ (ตัวอย่าง URI ในกรณีนี้คือ “/styles.css”) แต่โดยทั่วไปแล้วทรัพยากรอาจเป็นวัตถุนามธรรม (“/blogs/webdev/” - จุด ไปยังการพัฒนาบล็อก "เว็บ"" แทนที่จะเป็นไฟล์เฉพาะ)

ประเภทคำขอ HTTP (หรือที่เรียกว่าวิธี HTTP) จะบอกเซิร์ฟเวอร์ว่าเราต้องการดำเนินการใดกับทรัพยากร ในตอนแรก (ต้นทศวรรษที่ 90) สันนิษฐานว่าลูกค้าต้องการเพียงสิ่งเดียวจากทรัพยากร - เพื่อรับมัน แต่ตอนนี้ใช้โปรโตคอล HTTP คุณสามารถสร้างโพสต์ แก้ไขโปรไฟล์ ลบข้อความ และอื่นๆ อีกมากมาย และการกระทำเหล่านี้ยากที่จะรวมกับคำว่า "การรับ"

เพื่อแยกแยะการกระทำจากทรัพยากรในระดับวิธี HTTP จึงมีการสร้างตัวเลือกต่อไปนี้:

  • GET - รับทรัพยากร
  • POST - การสร้างทรัพยากร
  • PUT - อัปเดตทรัพยากร
  • DELETE - การลบทรัพยากร
โปรดทราบว่าข้อกำหนด HTTP ไม่ต้องการให้เซิร์ฟเวอร์เข้าใจวิธีการทั้งหมด (ซึ่งจริงๆ แล้วมีมากกว่า 4 วิธี) - ต้องใช้เพียง GET เท่านั้น และยังไม่ได้บอกเซิร์ฟเวอร์ว่าควรทำอย่างไรเมื่อได้รับคำขอด้วยวิธีการเฉพาะ วิธี. ซึ่งหมายความว่าเซิร์ฟเวอร์ตอบสนองต่อคำขอ DELETE /index.php HTTP/1.1 ไม่จำเป็นต้องลบหน้า index.php บนเซิร์ฟเวอร์ เช่นเดียวกับคำขอ GET /index.php HTTP/1.1 ไม่จำเป็นต้องคืนหน้า index.php ให้คุณ ก็สามารถลบทิ้งได้ เช่น :)

ส่วนที่เหลือเข้ามามีบทบาท

REST (Representational State Transfer) เป็นคำที่ Roy Fielding หนึ่งในผู้พัฒนาโปรโตคอล HTTP เปิดตัวในปี 2000 เป็นชื่อของกลุ่มหลักการในการสร้างเว็บแอปพลิเคชัน โดยทั่วไป REST ครอบคลุมพื้นที่กว้างกว่า HTTP - สามารถใช้ในเครือข่ายอื่นที่มีโปรโตคอลอื่นได้เช่นกัน REST อธิบายหลักการของการโต้ตอบระหว่างไคลเอนต์และเซิร์ฟเวอร์ ตามแนวคิดของ "ทรัพยากร" และ "กริยา" (สามารถเข้าใจได้ว่าเป็นเรื่องและภาคแสดง) ในกรณีของ HTTP ทรัพยากรจะถูกระบุโดย URI และคำกริยาคือวิธี HTTP

REST แนะนำให้ละทิ้งการใช้ URI เดียวกันสำหรับทรัพยากรที่แตกต่างกัน (นั่นคือ ที่อยู่ของบทความสองบทความที่แตกต่างกัน เช่น /index.php?article_id=10 และ /index.php?article_id=20 - นี่ไม่ใช่วิธี REST) ​​และ โดยใช้วิธีการ HTTP ที่แตกต่างกันสำหรับการดำเนินการที่แตกต่างกัน นั่นคือเว็บแอปพลิเคชันที่เขียนโดยใช้วิธี REST จะลบทรัพยากรเมื่อเข้าถึงด้วยวิธี HTTP DELETE (แน่นอนว่านี่ไม่ได้หมายความว่าจำเป็นต้องให้โอกาสในการลบทุกอย่างและทุกคน แต่ ใดๆคำขอลบของแอปพลิเคชันต้องใช้วิธี HTTP DELETE)

REST ช่วยให้โปรแกรมเมอร์สามารถเขียนเว็บแอปพลิเคชันที่ได้มาตรฐานและสวยงามกว่าเดิมเล็กน้อย เมื่อใช้ REST URI ที่จะเพิ่มผู้ใช้ใหม่จะไม่ใช่ /user.php?action=create (วิธี GET/POST) แต่เป็นเพียงแค่ /user.php (วิธี POST อย่างเคร่งครัด)

ด้วยเหตุนี้ เมื่อรวมข้อกำหนด HTTP ที่มีอยู่และวิธีการ REST เข้าด้วยกัน วิธี HTTP ต่างๆ ก็สมเหตุสมผลในที่สุด GET - ส่งคืนทรัพยากร, POST - สร้างทรัพยากรใหม่, PUT - อัปเดตทรัพยากรที่มีอยู่, DELETE - ลบออก

ปัญหา?

ใช่ มีปัญหาเล็กน้อยกับการใช้ REST ในทางปฏิบัติ ปัญหานี้เรียกว่า HTML

สามารถส่งคำขอ PUT/DELETE ได้โดยใช้ XMLHttpRequest โดยติดต่อกับเซิร์ฟเวอร์ด้วยตนเอง (เช่น ผ่าน curl หรือแม้แต่ผ่านทาง telnet) แต่คุณไม่สามารถสร้างแบบฟอร์ม HTML ที่ส่งคำขอ PUT/DELETE แบบเต็มได้

ประเด็นก็คือ ข้อกำหนด HTML ไม่อนุญาตให้คุณสร้างแบบฟอร์มที่ส่งข้อมูลอื่นนอกเหนือจากผ่าน GET หรือ POST ดังนั้นในการทำงานตามปกติกับวิธีอื่นคุณต้องเลียนแบบวิธีเหล่านั้นแบบเทียม ตัวอย่างเช่นใน Rack (กลไกบนพื้นฐานของการที่ Ruby โต้ตอบกับเว็บเซิร์ฟเวอร์ Rails, Merb และเฟรมเวิร์ก Ruby อื่น ๆ ถูกสร้างขึ้นโดยใช้ Rack) คุณสามารถเพิ่มฟิลด์ที่ซ่อนอยู่ให้กับแบบฟอร์มด้วยชื่อ "_method" และ ระบุชื่อของวิธีการเป็นค่า (เช่น "PUT") - ในกรณีนี้คำขอ POST จะถูกส่งไป แต่ Rack จะสามารถแกล้งทำเป็นว่าได้รับ PUT แทนที่จะเป็น POST

RESTful API สามารถสร้างได้ไม่เพียงแต่สำหรับบริการของบุคคลที่สามเท่านั้น สามารถใช้โดยแอปพลิเคชันหน้าเดียวสำหรับงานแบ็คเอนด์ ต่อไปนี้คือสิ่งพื้นฐานที่คุณต้องรู้เมื่อออกแบบอินเทอร์เฟซ

URL และการดำเนินการ

หลักการสำคัญของ REST คือการแบ่ง API ของคุณออกเป็นทรัพยากรเชิงตรรกะ ทรัพยากรเหล่านี้ได้รับการจัดการโดยใช้คำขอ HTTP ด้วยวิธีการที่เหมาะสม - GET, POST, PUT, PATCH, DELETE

ทรัพยากรต้องอธิบายด้วยคำนามพหูพจน์ การดำเนินการกับทรัพยากรมักจะถูกกำหนดโดยกลยุทธ์ CRUD และสอดคล้องกับวิธี HTTP ดังต่อไปนี้:

  • GET /api/users - รับรายชื่อผู้ใช้
  • GET /api/users/123 - รับผู้ใช้ที่ระบุ
  • POST /api/users - สร้างผู้ใช้ใหม่
  • PUT /api/users/123 - อัปเดตข้อมูลทั้งหมดของผู้ใช้ที่ระบุ
  • PATCH /api/users/123 - อัปเดตข้อมูลผู้ใช้บางส่วน
  • DELETE /api/users/123 - ลบผู้ใช้

หากทรัพยากรมีอยู่ในบริบทของทรัพยากรอื่นเท่านั้น URL ก็อาจมีความซับซ้อนได้:

  • GET /api/posts/9/comments - รับรายการความคิดเห็นสำหรับโพสต์หมายเลข 9
  • รับ /api/posts/9/comments/3 - รับความคิดเห็นหมายเลข 3 เพื่อโพสต์หมายเลข 9

เมื่อการกระทำบนวัตถุไม่สอดคล้องกับการดำเนินการ CRUD ก็ถือเป็นทรัพยากรแบบผสมได้:

  • POST /api/posts/9/like - ทำเครื่องหมายโพสต์ที่ 9 ว่าชอบ
  • ลบ /api/posts/9/like - ลบเครื่องหมาย "ถูกใจ" ออกจากโพสต์หมายเลข 9

การดำเนินการเพื่อสร้างและอัปเดตทรัพยากรจะต้องส่งคืนทรัพยากร

วิธีการ POST, PUT หรือ PATCH สามารถแก้ไขฟิลด์ทรัพยากรที่ไม่รวมอยู่ในคำขอได้ (เช่น ID วันที่สร้าง หรือวันที่อัปเดต) เพื่อหลีกเลี่ยงการบังคับให้ผู้ใช้ API ส่งคำขออีกครั้งเพื่อรับข้อมูลที่อัปเดต วิธีการดังกล่าวควรส่งคืนในการตอบกลับ

ตัวกรอง การเรียงลำดับ และการค้นหา

คุณสามารถใช้พารามิเตอร์ใดๆ ในคำขอ HTTP เพื่อปรับแต่งคำขอหรือจัดเรียงข้อมูลได้

  • GET /api/users?state=active - รายชื่อผู้ใช้ที่ใช้งานอยู่
  • GET /api/tasks?state=open&sort=priority,-created_at - รายการงานคงค้าง จัดเรียงตามลำดับความสำคัญและวันที่สร้าง (งานใหม่ก่อน)

การนำทางหน้า

เมื่อคุณต้องการเพิ่มข้อมูลเกี่ยวกับการนำทางเพจเพื่อตอบสนองต่อคำขอรายการออบเจ็กต์ คุณควรใช้ส่วนหัวของลิงก์ HTTP แทนที่จะเพิ่มตัวห่อข้อมูล

ตัวอย่างส่วนหัว:

ลิงค์: - rel = "ถัดไป", - rel="ก่อนหน้า", - rel="ครั้งแรก", - rel="สุดท้าย"

ค่าที่เป็นไปได้สำหรับ rel:

  • ถัดไป - หน้าถัดไปของผลลัพธ์
  • ก่อนหน้า - หน้าผลลัพธ์ก่อนหน้า
  • หน้าแรก - หน้าแรกของผลลัพธ์
  • สุดท้าย - หน้าสุดท้ายของผลลัพธ์

สิ่งสำคัญคือต้องปฏิบัติตามค่าเหล่านี้แทนที่จะสร้าง URL ของคุณเอง เนื่องจากบางครั้งการนำทางแบบแบ่งหน้าอาจขึ้นอยู่กับกฎที่ซับซ้อนมากกว่าแค่วนซ้ำผ่านหน้าต่างๆ

การแทนที่วิธี HTTP

เพื่อความเข้ากันได้กับเซิร์ฟเวอร์หรือไคลเอนต์บางตัวที่ไม่รองรับวิธี HTTP อื่นที่ไม่ใช่ GET และ POST การจำลองวิธีการเหล่านั้นอาจมีประโยชน์ ค่าของวิธีการจะถูกส่งผ่านในส่วนหัว X-HTTP-Method-Override และวิธีการนั้นจะถูกดำเนินการเป็นวิธีการ POST คำขอ GET ไม่ควรเปลี่ยนสถานะเซิร์ฟเวอร์!

รหัสสถานะ HTTP

  • 200 ตกลง - ตอบสนองต่อคำขอ GET, PUT, PATCH หรือ DELETE ที่ประสบความสำเร็จ
  • 201 สร้างแล้ว - ตอบสนองต่อคำขอ POST ซึ่งส่งผลให้มีการสร้างวัตถุใหม่ การตอบกลับจะต้องมาพร้อมกับส่วนหัว Location ที่ชี้ไปยัง URL ของทรัพยากร
  • 204 ไม่มีเนื้อหา - ตอบสนองต่อคำขอที่ดำเนินการสำเร็จซึ่งไม่ส่งคืนสิ่งใด ๆ (เช่น DELETE)
  • 404 ไม่พบ - ไม่พบวัตถุที่ร้องขอ
  • 500 ข้อผิดพลาดเซิร์ฟเวอร์ภายใน - ข้อผิดพลาดบนเซิร์ฟเวอร์

ในกรณีที่มีข้อผิดพลาด การตอบสนองอาจมีข้อมูลการดีบักสำหรับนักพัฒนา หากเป็นไปได้