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_s
I 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
end
And 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
end
P.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#