はじめに
Haskell向けに重めの記事を書いたりしたので、ちょっと箸休め。
elm-package.jsonには、"proxy"、という項目が設定できますが、使い方についてはまとまった記事が見当たらないので、メモとして書きます。
課題
本記事は、create-elm-appで作成したプロジェクトをベースにしています。elm-app eject
した後でもする前でも、どちらでも大丈夫です。本番稼働ではapache等のWebサーバで「/api」へのアクセスをバックエンドのAPIサーバにリバースプロキシするとして、開発ビルドではローカルPCで「elm-app start」あるいは「npm start」で動いてくれるWebサーバでも、同等のリバースプロキシ相当が働いてくれると便利なんですが、というのがテーマです。
elm-package.jsonの"proxy"設定
create-elm-appのドキュメント内の記述(Setting up API Proxy)を見ると、elm-package.jsonに、proxy" : "http://localhost:3004"
などと記述すると、APIコールを指定したURLに転送する、とのことです。
アクセス転送の条件は?
上記のドキュメントには、
Make sure the XHR requests set the Content-type: application/json and Accept: application/json.
と書いているのですが、そもそも何をもって「APIコール」とみなすのか?という書き方はしてくれないので、ちょっとわかりづらいです。
試行錯誤した結果は下記の通りです。
- アクセス転送は「開発ビルド時のみ」(elm-app eject前なら、elm-app start, 後ならnpm start)。本番ビルドでは適用されない
- アクセス転送する条件は、開発用ビルドで稼働するWebサーバへのhttpアクセスで、ヘッダに「Content-type: application/json」と「Accept: application/json」が含まれる場合。URLのパスは無関係。URL中のパスは変更されず、そのまま設定値のURLに転送される
Elmコードでの対応
APIアクセスをJSONで行う場合、「Content-type: application/json」は自動的に含まれるため、あとは「Accept: application/json」を明示的に含めてやればOKです。コードのサンプルはこんな感じになるかと思います。
apiHeader : List Http.Header
apiHeader = [Http.header "Accept" "application/json"]
apiGet : String -> Decode.Decoder a -> Http.Request a
apiGet url decoder =
let request =
{ method = "GET"
, headers = apiHeader
, url = "/api" ++ url
, body = Http.emptyBody
, expect = Http.expectJson decoder
, timeout = Nothing
, withCredentials = False
}
in Http.request request
上記の例のapiGetの引数decoderには、受け取りたい型のJSONデコーダを指定します。apiGet関数は、Http.sendの引数にセットして、APIコールを実行します。
注意点
elm-package.jsonに"proxy"を追加した後に、elm-package install等で、elm-package.jsonを変更する操作をした場合、この"proxy"の項目は消えてしまいます。ちょっと(?)不便ですね。
create-elm-appのissuesにて議論されていていたりしますが、今はどうしようもない模様です。