การพยายามออกแบบ API สำหรับแอปพลิเคชันภายนอกที่มีการคาดการณ์ล่วงหน้าสำหรับการเปลี่ยนแปลงนั้นไม่ใช่เรื่องง่าย แต่การคิดล่วงหน้าเล็กน้อยจะทำให้ชีวิตง่ายขึ้นในภายหลัง ฉันกำลังพยายามสร้างโครงร่างที่จะรองรับการเปลี่ยนแปลงในอนาคตในขณะที่ยังคงเข้ากันได้แบบย้อนกลับโดยปล่อยให้ตัวจัดการเวอร์ชันก่อนหน้าเข้าแทนที่
ข้อกังวลหลักของบทความนี้คือรูปแบบใดที่ควรปฏิบัติตามสำหรับจุดสิ้นสุดที่กำหนดไว้ทั้งหมดสำหรับผลิตภัณฑ์ / บริษัท ที่กำหนด
โครงการฐาน
ได้รับเทมเพลต URL ฐานของhttps://rest.product.com/
ผมได้วางแผนว่าบริการทั้งหมดอาศัยอยู่ภายใต้/api
พร้อมกับ/auth
และปลายทางที่ไม่ใช่ส่วนที่เหลืออื่น ๆ /doc
เช่น ดังนั้นฉันสามารถสร้างจุดปลายพื้นฐานดังนี้:
https://rest.product.com/api/...
https://rest.product.com/auth/login
https://rest.product.com/auth/logout
https://rest.product.com/doc/...
จุดบริการ
ตอนนี้สำหรับปลายทางเอง ความกังวลเกี่ยวกับPOST
, GET
, DELETE
ไม่ได้เป็นวัตถุประสงค์หลักของบทความนี้และเป็นกังวลกับการกระทำเหล่านั้นเอง
จุดปลายสามารถแบ่งออกเป็นเนมสเปซและการกระทำได้ แต่ละการกระทำจะต้องนำเสนอตัวเองในวิธีที่จะสนับสนุนการเปลี่ยนแปลงขั้นพื้นฐานในประเภทผลตอบแทนหรือพารามิเตอร์ที่จำเป็น
การใช้บริการแชทสมมุติที่ผู้ใช้ที่ลงทะเบียนสามารถส่งข้อความเราอาจมีจุดสิ้นสุดดังต่อไปนี้:
https://rest.product.com/api/messages/list/{user}
https://rest.product.com/api/messages/send
ตอนนี้เพื่อเพิ่มการรองรับเวอร์ชันสำหรับการเปลี่ยนแปลง API ในอนาคตซึ่งอาจแตกหัก เราสามารถเพิ่มลายเซ็นเวอร์ชันหลังจาก/api/
หรือหลังจาก/messages/
นั้น เมื่อกำหนดsend
จุดสิ้นสุดเราจะได้สิ่งต่อไปนี้สำหรับ v1
https://rest.product.com/api/v1/messages/send
https://rest.product.com/api/messages/v1/send
ดังนั้นคำถามแรกของฉันคือสถานที่ที่แนะนำสำหรับตัวระบุรุ่นคืออะไร
ผู้จัดการรหัสควบคุม
ดังนั้นตอนนี้เราได้สร้างขึ้นแล้วเราจำเป็นต้องสนับสนุนเวอร์ชันก่อนหน้าดังนั้นเราจึงต้องจัดการกับรหัสสำหรับเวอร์ชั่นใหม่แต่ละเวอร์ชั่นซึ่งอาจเลิกใช้ไปตามกาลเวลา สมมติว่าเรากำลังเขียนจุดปลายใน Java เราสามารถจัดการสิ่งนี้ผ่านแพ็คเกจ
package com.product.messages.v1;
public interface MessageController {
void send();
Message[] list();
}
นี่เป็นข้อได้เปรียบที่โค้ดทั้งหมดถูกคั่นผ่านเนมสเปซซึ่งการเปลี่ยนแปลงที่เกิดขึ้นจะหมายถึงสำเนาใหม่ของจุดบริการ ความเสียหายของสิ่งนี้คือรหัสทั้งหมดจะต้องคัดลอกและแก้ไขข้อผิดพลาดที่ต้องการนำไปใช้กับรุ่นใหม่และรุ่นก่อนหน้านี้จะต้องใช้ / ทดสอบสำหรับแต่ละสำเนา
อีกวิธีหนึ่งคือการสร้างตัวจัดการสำหรับแต่ละปลายทาง
package com.product.messages;
public class MessageServiceImpl {
public void send(String version) {
getMessageSender(version).send();
}
// Assume we have a List of senders in order of newest to oldest.
private MessageSender getMessageSender(String version) {
for (MessageSender s : senders) {
if (s.supportsVersion(version)) {
return s;
}
}
}
}
ตอนนี้แยกการกำหนดเวอร์ชันให้กับแต่ละจุดปลายทางและทำให้การแก้ไขข้อผิดพลาดกลับพอร์ตที่เข้ากันได้โดยในกรณีส่วนใหญ่จำเป็นต้องใช้เพียงครั้งเดียว แต่ก็หมายความว่าเราต้องทำงานอย่างเป็นธรรมมากขึ้นในแต่ละจุดสิ้นสุดแต่ละจุดเพื่อสนับสนุนสิ่งนี้
ดังนั้นจึงมีคำถามที่สองของฉัน "วิธีที่ดีที่สุดในการออกแบบรหัสบริการ REST เพื่อรองรับเวอร์ชันก่อนหน้าคืออะไร"