Heroku 謹製 環境変数を検証するライブラリ configvar

# はじめに
本投稿は [Heroku Advent Calendar 2016](http://qiita.com/advent-calendar/2016/heroku) の 第7日目の記事です。

※ いまは Heroku でも node.js が人気かと思いますが、 ruby 限定の話です。

Heroku でアプリケーションを稼動させていると、環境変数を利用する場面が多々あると思います。ruby だと [settingslogic](https://github.com/binarylogic/settingslogic) とか [config（rails-config）](https://github.com/railsconfig/config) を使って、環境ごとに環境変数を設定しているんじゃないかと思います。Heroku 謹製の gem で [configvar](https://github.com/heroku/configvar) という環境変数で設定されている値を検証する gem があったのでここで紹介してみます。それオワコンだよ、とか config でできるよって場合はごめんなさい。

<img width="1001" alt="スクリーンショット 2016-12-07 14.43.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/7046/c531c45e-4413-0c8f-b7c9-554dea8dc03c.png">


# configvar でできること

- 必須な環境変数とそうじゃない環境変数の明示
- 上記の環境変数の存在有無の検証
- 環境変数に設定されている値の検証

# Ruby スクリプトでやってみる

```ruby:hello.rb
require "configvar"

config = ConfigVar.define do
  required_string  :myname
end

puts "hello, world!"
```

こんな感じです。

```
$ruby hello.rb
/usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:34:in `block in required_string': A value must be provided for MYNAME (ConfigVar::ConfigError)
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:141:in `block in define_config'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:12:in `call'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:12:in `block in reload'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:11:in `each_value'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:11:in `reload'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar.rb:23:in `define'
	from config.rb:3:in `<main>'
$export MYNAME='John Doe'
$ruby hello.rb
hello, world!
```
ひっかかると `ConfigVar::ConfigError` というエラーが投げられます。

ちなみに、以下のように書き換えると

```ruby:hello.rb
require "configvar"

config = ConfigVar.define do
  required_int  :myint #required_int は整数かどうかを検証する
end

puts "hello, world!"
```
こうなります

```
$export MYINT='John Doe'
$ruby hello.rb
/usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:120:in `rescue in parse_int': John Doe is not a valid boolean for MYINT (ArgumentError)
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:118:in `parse_int'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:43:in `block in required_int'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:141:in `block in define_config'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:12:in `call'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:12:in `block in reload'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:11:in `each_value'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar/context.rb:11:in `reload'
	from /usr/local/lib/ruby/gems/2.2.0/gems/configvar-0.1.0/lib/configvar.rb:23:in `define'
	from hello.rb:3:in `<main>'
$export MYINT=1234
$ruby hello.rb
hello, world!
```

# rails でやってみる
乱暴なんですが、とりあえずこんな感じで。

```ruby:config/environment_variables.rb
require "configvar"
require "uuid"

config = ConfigVar.define do
  required_custom :uuid do |env|
    value = env['UUID']
    if UUID.validate(value)
      value
    else
      error_message = "A valid value must be provided for ENV['UUID']"
      raise ConfigVar::ConfigError.new(error_message)
    end
  end
end
```

```ruby:config/environment.rb
# Load the Rails application.
require_relative 'application'
require_relative 'environment_variables' #追記した
# Initialize the Rails application.
Rails.application.initialize!
```

この例だと、環境変数 `UUID` に `UUID::validate` を通過しない値が設定されていたとき、`A valid value must be provided for ENV['UUID'] (ConfigVar::ConfigError)` とエラーがでるようになります。

`ConfigVar.define` のなかが汚くなりそうだったり、なんかもっといい方法ありそうだけど、取り急ぎ〜。