2012年10月20日土曜日

heroku+SendGrid+Play2+JavaMailでメールを送る

今回は、heroku上にホスティングしたPlayframeworkベースのアプリケーションからメールを送信してみようというお話です。
※この記事は「heroku上でPlayframework2のwelcomeページを表示させることはできた」という前提で進めます

herokuからメールを送る


まず、そもそもherokuからどうやってメールを送るの?というところから。

手段としては、外部にSMTPサーバを用意するってのが一番単純で、ググると「herokuからGMailのSMTP叩く」みたいなのは出てきます。出てくるんですが、これやるにはそのSMTPの認証情報を直書きしてpushしなきゃいけないので、「できるんだけど扱いにくいなぁ」という印象でした。うまくやる方法あるのかな?あったら教えて下さい。

で、今回はherokuアドオンに頼ることにします。

https://addons.heroku.com/sendgrid

SendGridというアドオンがあったので使ってみることにしました。
1日200通まで無料の「Starter」プランで送れるそうです。どんなメールを送るかによりますが、とりあえず試すには十分すぎるのでこれを使います。
コマンドでもWebからでもいいので、SendGrid Starterをサクっとアプリケーションに追加しちゃってください。

このSendGridというアドオンはどのような仕組みでメールを送っているかというと、

  • SMTPサーバ自体は外部にある
  • 認証情報をアドオンから環境変数に渡してくれる
  • あとはSMTP叩くだけ

という至極シンプルなものです。

これだけ書けばどうやってメール送るかは想像できるかもしれませんが、一応ひと通り書いていきます。

認証情報をPlayアプリケーションに渡す


herokuでPlayframework2ベースアプリケーションを動かすにはProcfileってのを作ったと思うので、これを編集して、環境変数をJavaシステムプロパティとしてアプリケーションに引渡します。DBを使わないメールのみ送れる一番単純なアプリだとこんな感じ。

web: target/start -Dhttp.port=${PORT} ${JAVA_OPTS} -Dmail.smtp.host=smtp.sendgrid.net -Dmail.smtp.port=587 -Dmail.smtp.auth=true -Dmail.smtp.user=${SENDGRID_USERNAME} -Dmail.smtp.pass=${SENDGRID_PASSWORD}

※1行です

SENDGRID_USERNAME、SENDGRID_PASSWORDという環境変数で認証情報が渡ってくるので、適当なプロパティ名つけて渡してやりましょう。mail.smtp.host、mail.smtp.port、mail.smtp.authについては、別にここで渡さなきゃいけないってことはないけども、設定値をハードコーディングしない的な意味でも、どうせJavaMailでPropertiesオブジェクトが必要だからこの方が楽という意味でも、システムプロパティとして渡してやった方が良いかと思います。

JavaMailでメール送信


あとはメール送るだけです。今回はJavaMail使います。

http://www.oracle.com/technetwork/java/javamail/index.html

もちろんmavenリポジトリ上にあるので、project/Build.scalaに1行追加すれば依存設定完了。

val appDependencies = Seq(
  // Add your project dependencies here,
  "javax.mail" % "mail" % "1.4.5"
)

で、あとはJavaMailから、システムプロパティの値を使ってメールを送信してやるだけ。



※エラーハンドリングとかWebアプリ自体の認証とかせず、メール送信部分だけを記述しています

JavaMailの送信手順をScalaで記述しただけで、工夫とか何もしてませんけどね。
普通にこれで送信できます。

ね、簡単でしょ?

2012年8月28日火曜日

lift-jsonのextractで痒いところに手を伸ばす

lift-json便利ですね。Play2に組み込まれてるJsonも「型クラスかっけー」って感じで好きですけど、Playを使わないところではやっぱりlift-jsonがデファクトっぽい感じになってるかなーと思います。
で、lift-jsonでJsonからモデルにマッピングするにはどうするのかなーと思って検索してみると、大抵こちらに行き着きます。

Lift Json の case class への変換がとても便利な件 | scalaとか・・・

これ、すっげー便利なんですけど、実際に使ってみると、そのままじゃうまくいかない場面が出てくるんですよ。
なので、今回は「うまくいかない場面」 = 「痒いところ」に手を伸ばしてみます。

うまくいかない場面1: case objectへのマッピング


例えばこんな風に、Javaでいう列挙型みたいなモデルを作った場合。



で、この3つにそれぞれ0,1,2が割り当てられていて、Jsonでは例えば
{ carrier: 0 }
といった表現がされているとします。

この場合は、この型に変換する機構をlift-jsonは持っていないので、作ってやる必要があります。



このようにSerializerを作っておくと、Formatsに組み込むことができるので、以下のように自作Serializerを組み込んだ新しいFormatsを使ってextractできます。





うまくいかない場面2: Jsonの構造がちょっと違う


例:楽天ウェブサービスの市場商品検索2

これ、返りのJsonが以下のような構造をしています

{
  xxx: yyy
  ...
  Items: [
    {
      Item: {
      }
    },
    {
      Item: {
      }
    }
  ]
}

なぜかItemsとItemだけ頭文字が大文字なのかとか、ItemsのArrayの中身がItemそのものではなく、Itemというフィールドを持ったオブジェクトなのかとかツッコミたい感じです。ツッコミたいだけならいいんですけど、デフォルトのextract一発変換に頼ろうと思うとこういうのが結構ネックになるんですよね。
これ、「うまくいかない場面1」と同じようにSerializerを作っちゃってもいいんですけど、他にもたくさんの要素を含んでいて、ほんの一部だけを修正するためにSerializerを作るのはめんどうです。なので、こういう場合はJsonAST側を都合の良いようにいじっちゃった方が早いです。

変換にはtransformを使います。こいつ、再帰的にJsonASTを操作してくれるので、簡単にASTをいじれます。
詳しくはlift-jsonのソース見ちゃったほうが早いです。



こんな感じ。

2012年7月24日火曜日

永続化の前後をクラスで表現する

※本エントリの内容は「たぶんコレでいいんじゃない?むしろ違ったら教えて下さい」的な内容です。

DBにエンティティを永続化するというシチュエーションを考える。
例えばPersonというエンティティとしよう。



これをDBに保存するなら、PrimaryKeyが必要だ。ま、普通はIDを付けるでしょう。





さて、問題は、「ID採番前のPersonはどう表現するの?」という話。

案1. id = 0 とか、負の数を「採番前」ということにする

冗談です。

案2. idの型をOptionにする



確かに「IDの有無」を表現はできてるが、これだと例えば「これから採番するPersonのリスト」のような型が作りにくいです。

案3. オブジェクト指向っぽく行けばいいんじゃない?

いろいろ考えたんだけど落ち着いたのがここ。あんまカッコイイ答えじゃないんだけどね。
ただ、「case classにする」ってところだけは守るという制約でScalaで書こうと思うと、やっぱりちょっと考えないといけない。



で、こうなった。id以外のメンバは何回も書いてるのが正直気に入らない。でも、使うときは多分これが一番気持ちよく使えると思う。

もっと良い書き方募集。

2012年7月17日火曜日

Windowsガジェット環境でのsubstr

Windowsガジェット(最初はVistaサイドバーガジェットとか呼ばれてたもの)って、もはや生みの親であるMicrosoftからも「Windows8が出たら要らないよね」って言われちゃったかわいそうな子だけれども、でもなんだかんだ言ってもWindows7使ってるうちは何かと便利なツールなわけで、結構馬鹿にできないと思うんです。

というわけで、to-banからJSON引っ張って今日の"当番"をWindowsガジェットに表示させておくと捗るぞ、と思って手を出した。

が、すっげーアホくさいところでハマったので、記録しておく。

それがString.substr関数。

これ、第一引数に負の数を渡すと、現在の標準では文字列の後ろから数えてくれるんだけど、Windowsガジェット環境(や超古いブラウザ)では負の数を渡すと何もしてくれなくなる。



厄介なのは、IE9が入ってるWindows環境でも、ガジェット上ではガジェット環境での挙動を示すということ。「IEで動けばガジェットでも大体動くだろー」とタカをくくってるとハマる(体験談)

2012年7月16日月曜日

PlayでurlFormEncodedなデータを受け取る

Playでformからの入力を受け取る場合は、ファイルアップロードが必要な場合を除けば、大抵の場合はurlFormEncodedを通してデータを受け取る事になると思う(Ajaxとかいう解はとりあえず考えない)。例えば以下の様なコードになる。



言うまでもなく、Requestからデータを取り出す部分が無駄に長い。
これは、urlFormEncodedのbodyの型がMap[String, Seq[String]]だから。もちろんプロトコル上はこの型が妥当なのだが、大抵の場合はValueは1つだけ値があれば十分なので、Seqから1個取り出すのが冗長に感じられるわけだ。

じゃあ、ということで、以下の様な関数を作ってやればとりあえず短くはなる。



短くはなるんだけど、ただ単純に処理を切り出しただけ。使ってみるとわかるけど、あんまりScalaっぽくない。
せっかくScala使ってるんだから、型クラス使いたいよね!

というわけで、こうなった。



paramOpt関数がControllerから呼び出す関数。
こいつはimplicit parameterでExtractor[T]を受け取っていて、そのExtractorのextract関数を利用してデータ抽出を行う。
paramOpt関数自信も型パラメータを持っていて、そこに指定された型に合ったExtractorが選択されて使われるわけだ。
extractorByみたいな関数も用意しておけば、IntExtractorの様に、既存のExtractorと型変換用関数を組み合わせて新たなExtractorを構成するのも簡単だ。

Extractor[T]を使って最初のPersonの例を書きなおすとこうなる。



スッキリ!



追記:

extractorByの中身、何をやってるかって言うと、A => Option[B] と B => Option[C] を組み合わせて A => Option[C] を作ってるんだよね。で、


って呟いたら、反応されてた。



やっべ、kleisliわかんねぇ。勉強します。。。

2012年3月9日金曜日

ソースコード

コードをBloggerに載せるのって、JavaScript+CSSでSyntaxHighlightを頑張ってくれるサービス使うのと、Gits貼るのとどっちがいいかねぇ?

Gistの方が楽そうだけどw


とりあえずGistで行ってみようと思う。

2012年3月8日木曜日

初めに

一応「学生」じゃなくてプロとしてエンジニアになったわけで、何かをoutputしたい感が出てきたから、やっぱブログかな?的なノリでとりあえず作ってみる。