DRY Conventional API Provider Host Setting by Environment Fallback and Alias Mapping
For my content management system gem http://Home-Page.Software I wanted to support different APIs and use the right host for the current environment by a fallback chain.
Therefor I need to handle aliases of user environment names and environments not supported by an API provider.
Given these settings from a Rails initializer powered by rails-settings-cached (you have to use development, test, staging or production as key):
Setting.defaults[
  'apis.providers.volontariat.hosts.development'
] = 'http://localhost:3001'
Setting.defaults[
  'apis.providers.volontariat.hosts.production'
] = 'http://Volontari.at' # currently down :-(I wanted something like this:
host = ApiProviderHost.new('volontariat', Rails.env).to_sI expect it to behave like this:
describe ApiProviderHost do
  describe '#to_s' do
    it 'behaves like this' do
      provider = 'name_of_host'
      Setting.defaults[
        'apis.providers.name_of_host.hosts.development'
      ] = 'http://localhost:3001'
      # no fallback or alias mapping needed
      expect(
        described_class.new(provider, 'development').to_s
      ).to be == 'http://localhost:3001'
      # fallback to development
      expect(
        described_class.new(provider, 'test').to_s
      ).to be == 'http://localhost:3001'
      # alias mapping needed
      expect(
        described_class.new(provider, 'dev').to_s
      ).to be == 'http://localhost:3001'
      # alias not found
      expect{
        described_class.new(provider, 'unknown_environment').to_s
      }.to raise_error(
        NotImplementedError, 
        'Your environment is unknown. Please update alias mapping!'
      )
      # environment not supported by provider
      expect{
        described_class.new(provider, 'staging').to_s
      }.to raise_error(
        NotImplementedError, 
        'The API provider does not support your environment!'
      )
    end
  end
endAnd I implemented this class:
class ApiProviderHost
  ENVIRONMENTS = [:development, :test, :staging, :production]
  ALIASES = { 
    dev: :development, testing: :test, stage: :staging, show: :staging, 
    live: :production, prod: :production 
  }
  FALLBACKS = { 
    development: [:development, :test, :staging, :production], 
    test: [:test, :development, :staging, :production],
    staging: [:staging, :production],
    production: [:production]
  }
  def initialize(provider, working_environment)
    @provider = provider
    @environment = working_environment.to_s.to_sym
  end
  def setting_namespace
    "apis.providers.#{@provider}.hosts"
  end
  def environment
    if ENVIRONMENTS.include?(@environment)
      @environment
    else
      ALIASES[@environment] || raise(
        NotImplementedError, 
        'Your environment is unknown. Please update alias mapping!'
      )
    end
  end
  def to_s
    host = nil
    FALLBACKS[environment].each do |provider_environment|
      host = Setting["#{setting_namespace}.#{provider_environment}"]
      break if host
    end
    unless host
      raise(
        NotImplementedError, 
        'The API provider does not support your environment!'
      )
    end
    host
  end
endP.S.: In the past I lived with always setting a host for each environment and without environment alias mapping but this was not DRY:
Setting.defaults[
  'apis.providers.volontariat.hosts.development'
] = 'http://localhost:3001'
Setting.defaults[
  'apis.providers.volontariat.hosts.test'
] = 'http://localhost:3001'
Setting.defaults[
  'apis.providers.volontariat.hosts.staging'
] = 'http://Volontari.at'
Setting.defaults[
  'apis.providers.volontariat.hosts.production'
] = 'http://Volontari.at'
# optional: I also put the little envionment alias mapping code here if you can't live without it
environment = { 
    dev: :development, testing: :test, stage: :staging, show: :staging, 
    live: :production, prod: :production 
  }[Rails.env.to_s.to_sym] || Rails.env
host = Setting[
  "apis.providers.volontariat.hosts.#{environment}"
]Written by Mathias Gawlista
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
 #Ruby 
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#

 
 
 
 
