เมื่อคุณใช้ Ruby เพื่อห่อ API คุณต้องมีวิธีกำหนดค่า บางที wrapper อาจต้องการชื่อผู้ใช้และรหัสลับ หรืออาจเป็นแค่โฮสต์
มีหลายวิธีในการจัดการกับสิ่งนี้ แล้วควรเลือกอันไหนดี?
วิธีที่ง่ายและเป็นสากล
คุณอาจต้องการให้บริการของคุณทำเหมือนมีอยู่ทุกที่ ไม่ว่าคุณจะอยู่ที่ไหนในแอป คุณก็พร้อมใช้ มิฉะนั้น คุณจะใช้เวลาสามบรรทัดในการกำหนดค่าสำหรับทุกบรรทัดที่ใช้!
คุณสามารถทำให้การกำหนดค่าเป็นสากลโดยใช้ค่าคงที่หรือแอตทริบิวต์ของคลาส:
ProductApi.root = "https://staging-host.example.com/"
ProductApi.user = "justin"
ProductApi.secret = "mysecret123"
def show
@product = ProductApi.find(params[:id])
end
อัญมณีจำนวนมากใช้รูปแบบนี้ มันค่อนข้างง่ายในการเขียนและใช้งานง่ายมาก แต่มันมีปัญหาใหญ่อยู่บ้าง:
-
คุณสามารถมี
ProductApi
ได้เพียงตัวเดียวเท่านั้น .หากคุณต้องการใช้ Product API เป็นผู้ใช้สองคน หรือเข้าถึงเซิร์ฟเวอร์ที่ต่างกันจากแอปเดียว แสดงว่าคุณโชคไม่ดี
-
ProductApi
มีข้อมูลทั่วโลกที่ง่ายต่อการเปลี่ยนแปลงโดยไม่ได้ตั้งใจหากเธรดหรือส่วนหนึ่งของแอปของคุณเปลี่ยน
ProductApi.user
, อย่างอื่นโดยใช้ProductApi
จะแตก และนั่นก็เจ็บปวด ข้อบกพร่องที่จะติดตาม
ดังนั้น ตัวแปรคลาสจึงมีปัญหาบางอย่าง จะเกิดอะไรขึ้นถ้าคุณกำหนดค่า อินสแตนซ์ ของคลาส Product API ของคุณแทนหรือไม่
หน้าตาจะเป็นอย่างไรเมื่อใช้ #initialize
?
หากคุณใช้อินสแตนซ์ คุณจะต้องสร้างและกำหนดค่า Wrapper API เมื่อคุณต้องการ:
def show
product_api = ProductApi.new(
root: "https://staging-host.example.com/",
user: "justin",
secret: "mysecret123")
@product = product_api.find(params[:id])
end
ตอนนี้คุณสามารถส่งรายละเอียดต่างๆ ไปยัง API ของคุณทุกครั้งที่ใช้งาน ไม่มีวิธีการหรือเธรดอื่นใดที่ใช้อินสแตนซ์ของคุณ คุณจึงไม่ต้องกังวลว่าจะเปลี่ยนโดยที่คุณไม่รู้ตัว
นี้ดูเหมือนดีกว่า แต่ก็ยังไม่ง่ายอย่างที่ควรจะเป็น เพราะคุณต้องกำหนดค่า API ทุกครั้ง คุณใช้มัน
ส่วนใหญ่คุณไม่สนใจว่า API ถูกตั้งค่าอย่างไร คุณแค่ต้องการใช้กับตัวเลือกที่เหมาะสม แต่เมื่อคุณทำงานกับอินสแตนซ์ ทุกส่วนของแอปที่ใช้ API จะต้องรู้วิธีกำหนดค่า
แต่มีวิธีรับความสะดวกสบายในการเข้าถึงทั่วโลก โดยใช้ค่าเริ่มต้นที่ดี ในขณะที่ยังคงสามารถเปลี่ยนแปลงได้หากต้องการ
และรูปแบบนี้ปรากฏขึ้นตลอดเวลาในสถานที่ที่น่าสนใจ:การพัฒนา OS X และ iOS
คุณจะได้รับค่าเริ่มต้นที่ดีอย่างไร และ ความยืดหยุ่น?
จะเกิดอะไรขึ้นถ้าคุณสามารถกำหนดค่าแต่ละอินสแตนซ์ของตัวห่อ API ของคุณ แต่คุณยังมีอินสแตนซ์ "เริ่มต้น" ส่วนกลางเมื่อคุณไม่สนใจ
คุณจะเห็นรูปแบบ "defaultSomething" หรือ "sharedWhatever" นี้ใน SDK ของ iOS และ Mac OS:
[[NSURLSession sharedSession] downloadTaskWithURL:@"https://www.google.com"];
[[NSFileManager defaultManager] removeItemAtPath:...];
และคุณยังสามารถขออินสแตนซ์ของคลาสเหล่านี้ได้หากต้องการมากกว่าค่าเริ่มต้น:
NSURLSession *session = [NSURLSession sessionWithConfiguration:...];
NSFileManager fileManager = [[NSFileManager alloc] init];
คุณสามารถสร้างสิ่งนั้นใน Ruby ด้วย default_api
วิธีการเรียน:
def show
@product = ProductApi.default_product_api.find(params[:id])
end
...
def show_special
special_product_api = ProductApi.new(
root: "https://special-product-host.example.com/"
user: "justin"
secret: "mysecret123")
@special_product = special_product_api.find(params[:id])
end
และการใช้งานอาจมีลักษณะดังนี้:
class ProductApi
def initialize(root:, user:, secret:)
@root, @user, @secret = root, user, secret
end
def self.default_api
@default_api ||= new(
root: ENV['PRODUCT_API_ROOT'],
user: ENV['PRODUCT_API_USER'],
secret: ENV['PRODUCT_API_SECRET'])
end
def find(product_id)
...
end
end
ที่นี่ ฉันใช้ตัวแปรสภาพแวดล้อมใน default_api
แต่คุณยังสามารถใช้ไฟล์ปรับแต่งได้ และคุณสามารถเปลี่ยน ||=
เพื่อใช้ที่จัดเก็บเธรดหรือร้องขอในเครื่องแทน
แต่นี่เป็นการเริ่มต้นที่ดี
อัญมณีส่วนใหญ่ที่ฉันเคยเห็น เช่น Twitter gem จะช่วยให้คุณกำหนดค่าและสร้างแต่ละอ็อบเจ็กต์ API เมื่อคุณต้องการ นี่เป็นวิธีแก้ปัญหาที่ดี (แม้ว่าปกติฉันจะเห็นคนกำหนดสิ่งเหล่านี้ให้กับ globals อยู่แล้ว )
แต่ถ้าคุณก้าวไปอีกขั้น และใช้ออบเจ็กต์เริ่มต้นที่กำหนดค่าไว้ล่วงหน้าด้วย คุณจะมีช่วงเวลาที่สะดวกสบายขึ้นมาก