Khi bạn sử dụng Ruby để bọc một API, bạn phải có cách để cấu hình nó. Có thể trình bao bọc cần tên người dùng và khóa bí mật hoặc có thể chỉ là máy chủ lưu trữ.
Có một số cách khác nhau để xử lý điều này. Vậy bạn nên chọn cái nào?
Cách dễ dàng, toàn cầu
Bạn có thể muốn dịch vụ của mình hoạt động như mọi khi. Bất kể bạn đang ở đâu trong ứng dụng của mình, bạn luôn có ứng dụng sẵn sàng để sử dụng. Nếu không, bạn sẽ tốn ba dòng định cấu hình nó cho mỗi dòng sử dụng nó!
Bạn có thể đặt cấu hình toàn cục, sử dụng các hằng số hoặc thuộc tính lớp:
ProductApi.root = "https://staging-host.example.com/"
ProductApi.user = "justin"
ProductApi.secret = "mysecret123"
def show
@product = ProductApi.find(params[:id])
end
Rất nhiều đá quý sử dụng mẫu này. Nó khá dễ viết và thực sự dễ sử dụng. Nhưng nó có một số vấn đề lớn:
-
Bạn chỉ có thể có một
ProductApi
.Nếu bạn muốn sử dụng API sản phẩm với tư cách là hai người dùng khác nhau hoặc truy cập các máy chủ khác nhau từ một ứng dụng, thì bạn đã không gặp may.
-
ProductApi
có dữ liệu toàn cầu dễ vô tình thay đổi.Nếu một chuỗi hoặc một phần ứng dụng của bạn đã thay đổi
ProductApi.user
, mọi thứ khác bằng cách sử dụngProductApi
sẽ phá vỡ. Và đó là những đau đớn lỗi cần theo dõi.
Vì vậy, các biến lớp có một số vấn đề. Điều gì sẽ xảy ra nếu bạn định cấu hình phiên bản của lớp API sản phẩm của bạn, thay vào đó?
Với #initialize
?
Nếu bạn đã sử dụng các phiên bản, bạn sẽ tạo và định cấu hình trình bao bọc API của mình khi cần:
def show
product_api = ProductApi.new(
root: "https://staging-host.example.com/",
user: "justin",
secret: "mysecret123")
@product = product_api.find(params[:id])
end
Bây giờ, bạn có thể chuyển các chi tiết khác nhau đến API của mình bất cứ khi nào bạn sử dụng nó. Không có phương thức hoặc chuỗi nào khác đang sử dụng phiên bản của bạn, vì vậy bạn không phải lo lắng về việc nó thay đổi mà bạn không biết.
Điều này có vẻ tốt hơn. Nhưng mọi chuyện vẫn không dễ dàng như mong đợi. Vì bạn phải định cấu hình API của mình mọi lúc bạn sử dụng nó.
Hầu hết thời gian bạn không quan tâm API được thiết lập như thế nào, bạn chỉ muốn sử dụng nó với các tùy chọn lành mạnh. Nhưng khi bạn đang làm việc với các phiên bản, mọi phần của ứng dụng của bạn sử dụng API phải biết cách định cấu hình nó.
Nhưng có một cách để có được sự thuận tiện của truy cập toàn cầu, sử dụng các giá trị mặc định tốt, trong khi vẫn có thể thay đổi nó nếu bạn cần.
Và mẫu này xuất hiện mọi lúc ở một nơi thú vị:phát triển OS X và iOS.
Làm cách nào để bạn có được giá trị mặc định tốt và tính linh hoạt?
Điều gì sẽ xảy ra nếu bạn có thể định cấu hình từng phiên bản của trình bao bọc API của mình, nhưng bạn cũng có một phiên bản "mặc định" chung khi bạn không quan tâm?
Bạn sẽ thấy mẫu “defaultSomething” hoặc “sharedW Anything” này trên SDK iOS và Mac OS:
[[NSURLSession sharedSession] downloadTaskWithURL:@"https://www.google.com"];
[[NSFileManager defaultManager] removeItemAtPath:...];
Và bạn vẫn có thể yêu cầu các phiên bản của các lớp này nếu bạn cần nhiều hơn những gì mặc định cung cấp cho bạn:
NSURLSession *session = [NSURLSession sessionWithConfiguration:...];
NSFileManager fileManager = [[NSFileManager alloc] init];
Bạn có thể tạo thứ gì đó tương tự trong Ruby, với default_api
phương thức lớp:
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
Và việc triển khai có thể trông giống như sau:
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
Ở đây, tôi đã sử dụng các biến môi trường trong default_api
, nhưng bạn cũng có thể sử dụng các tệp cấu hình. Và bạn có thể chuyển đổi ||=
để sử dụng chuỗi lưu trữ cục bộ hoặc yêu cầu thay thế.
Nhưng đây là một khởi đầu tốt.
Hầu hết các đá quý mà tôi đã thấy, như đá quý Twitter, sẽ yêu cầu bạn định cấu hình và tạo từng đối tượng API khi bạn cần chúng. Đây là một giải pháp OK (mặc dù tôi thường thấy mọi người gán những thứ này cho hình cầu dù sao ).
Nhưng nếu bạn tiến thêm một bước nữa và cũng sử dụng đối tượng mặc định được định cấu hình trước, bạn sẽ có thời gian thoải mái hơn nhiều.