Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby API 래퍼를 구성하는 3가지 방법

Ruby를 사용하여 API를 래핑할 때 구성할 방법이 있어야 합니다. 래퍼에 사용자 이름과 비밀 키가 필요하거나 호스트만 필요할 수도 있습니다.

이를 처리하는 몇 가지 다른 방법이 있습니다. 어떤 것을 선택해야 할까요?

쉽고 글로벌한 방법

서비스가 항상 주변에 있는 것처럼 작동하기를 원할 수 있습니다. 앱의 위치에 상관없이 바로 사용할 수 있습니다. 그렇지 않으면 사용하는 모든 라인에 대해 3줄을 구성하는 데 소비하게 됩니다!

상수 또는 클래스 속성을 사용하여 구성을 전역으로 만들 수 있습니다.

config/initializers/product_api.rb
ProductApi.root = "https://staging-host.example.com/"
ProductApi.user = "justin"
ProductApi.secret = "mysecret123"
앱/컨트롤러/제품_컨트롤러.rb
def show
  @product = ProductApi.find(params[:id])
end

많은 보석이 이 패턴을 사용합니다. 쓰기도 쉽고 사용하기도 정말 쉽습니다. 하지만 몇 가지 큰 문제가 있습니다.

  • ProductApi는 하나만 가질 수 있습니다. .

    Product API를 두 명의 다른 사용자로 사용하거나 단일 앱에서 다른 서버에 접속하려는 경우 운이 좋지 않습니다.

  • ProductApi 실수로 변경하기 쉬운 글로벌 데이터가 있습니다.

    스레드 또는 앱의 일부가 ProductApi.user를 변경한 경우 , ProductApi를 사용하는 기타 모든 것 깨질 것입니다. 그리고 그것들은 고통합니다. 추적할 버그.

따라서 클래스 변수에는 몇 가지 문제가 있습니다. 인스턴스를 구성했다면? 대신 Product API 클래스의?

#initialize를 사용하면 어떻게 될까요? ?

인스턴스를 사용한 경우 필요할 때 API 래퍼를 만들고 구성합니다.

앱/컨트롤러/제품_컨트롤러.rb
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에서 이와 유사한 것을 빌드할 수 있습니다. 클래스 메서드:

앱/컨트롤러/제품_컨트롤러.rb
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 객체를 구성하고 생성하도록 했습니다. 이것은 괜찮은 해결책입니다(보통 사람들이 어쨌든 전역에 할당하는 것을 봅니다. ).

그러나 한 단계 더 나아가 미리 구성된 기본 개체도 사용하면 훨씬 더 편안한 시간을 보낼 수 있습니다.