Ruby를 사용하여 API를 래핑할 때 구성할 방법이 있어야 합니다. 래퍼에 사용자 이름과 비밀 키가 필요하거나 호스트만 필요할 수도 있습니다.
이를 처리하는 몇 가지 다른 방법이 있습니다. 어떤 것을 선택해야 할까요?
쉽고 글로벌한 방법
서비스가 항상 주변에 있는 것처럼 작동하기를 원할 수 있습니다. 앱의 위치에 상관없이 바로 사용할 수 있습니다. 그렇지 않으면 사용하는 모든 라인에 대해 3줄을 구성하는 데 소비하게 됩니다!
상수 또는 클래스 속성을 사용하여 구성을 전역으로 만들 수 있습니다.
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
를 사용하면 어떻게 될까요? ?
인스턴스를 사용한 경우 필요할 때 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가 설정되는 방식에 신경 쓰지 않고 정상적인 옵션과 함께 사용하고 싶을 뿐입니다. 하지만 인스턴스로 작업할 때 API를 사용하는 앱의 모든 부분은 구성 방법을 알아야 합니다.
그러나 필요한 경우 변경할 수 있는 동시에 좋은 기본값을 사용하여 전역 액세스의 편리함을 얻을 수 있는 방법이 있습니다.
이 패턴은 OS X 및 iOS 개발이라는 흥미로운 위치에서 항상 나타납니다.
좋은 기본값을 얻는 방법 및 유연성?
API 래퍼의 각 인스턴스를 구성할 수 있지만 관심이 없을 때 전역 "기본" 인스턴스도 있다면 어떨까요?
iOS 및 Mac OS SDK 전체에서 다음과 같은 'defaultSomething' 또는 'sharedWhatever' 패턴이 표시됩니다.
[[NSURLSession sharedSession] downloadTaskWithURL:@"https://www.google.com"];
[[NSFileManager defaultManager] removeItemAtPath:...];
기본적으로 제공되는 것보다 더 많은 것이 필요한 경우 이러한 클래스의 인스턴스를 계속 요청할 수 있습니다.
NSURLSession *session = [NSURLSession sessionWithConfiguration:...];
NSFileManager fileManager = [[NSFileManager alloc] init];
default_api
를 사용하여 Ruby에서 이와 유사한 것을 빌드할 수 있습니다. 클래스 메서드:
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과 같이 내가 본 대부분의 gem은 필요할 때 각 API 객체를 구성하고 생성하도록 했습니다. 이것은 괜찮은 해결책입니다(보통 사람들이 어쨌든 전역에 할당하는 것을 봅니다. ).
그러나 한 단계 더 나아가 미리 구성된 기본 개체도 사용하면 훨씬 더 편안한 시간을 보낼 수 있습니다.