Elixirで最もシンプルなJSON RESTful API

フレームワークなしでElixirにJSON APIエンドポイントを実装する方法は?







翻訳者から:

この記事では、Hello、World!と見なすことができる非常に単純なWebアプリケーションの例を示します。 Elixirで最もシンプルなAPIを作成します。

サンプルコードは、ライブラリの現在のバージョンに合わせて若干変更されています。

変更が加えられた完全なサンプルコードはGitHub見ることができます。













新しい言語の課題



多くの開発者がRuby世界からElixirに来ています。 これは、利用可能なライブラリとフレームワークの数の点で非常に成熟した環境です。 エリクサーでは、そのような成熟度では十分でない場合があります。 サードパーティのサービスが必要な場合、適切な検索の結果は次のようになります。









ElixirのシンプルなJSON API









びっくりするかもしれませんが、 Rubyは常にレールに乗っているわけではありませんRuby on Rails、覚えていますか?-翻訳者注 )。 また、出席するためにウェブとのコミュニケーションも常に必要とされるわけではありません。 この特定のケースでは、ウェブについて話しましょう。







単一のRESTfulエンドポイントの実装に関しては、通常多くのオプションがあります。









これらは私が個人的に使用したツールの例です。 私の同僚はシナトラのユーザーに満足しています。 彼らはなんとか花見を試すことができました。 現在の気分によっても、自分に合ったオプションを選択できます。







しかし、エリクサーに切り替えたとき、選択肢が限られていたことがわかりました。 いくつかの代替の「フレームワーク」(明白な理由のためにここでは言及しません)がありますが、それらを使用することはほとんど不可能です!







私は、これまでインターネットで言及されたすべての図書館を整理するのに一日中費やしました。 Slackボットとして行動して、単純なHTTP2サーバーをHerokuデプロイしようとしましたが、その日のうちに降伏しました。 文字通り、私が見つけたオプションはどれも基本的な要件を実装できませんでした。







常に解決策ではない-フェニックス



フェニックスは、私のお気に入りのWebフレームワークです。それは単に冗長な場合があるだけです。 私はそれを使いたくありませんでした。1つのエンドポイントのためだけにフレームワーク全体をプロジェクトに引き込みました。 そして、それが非常に単純であることは重要ではありません。







既に述べたように、見つかったすべてのライブラリがニーズに適していないか(基本的なルーティングとJSONのサポートが必要でした)、Herokuに簡単かつ迅速にデプロイするには十分ではなかったため、既製のライブラリも使用できませんでした。 一歩下がったと思いました。













しかし、実際には、フェニックス自体は何かに基づいて構築されていますよね?







プラグとカウボーイが救いに来ます



Rubyで真にミニマルなサーバーを作成する必要がある場合は、Ruby Webサーバー用のモジュラーインターフェイスであるrack



使用するだけです。







幸いなことに、Elixirでも同様の機能が利用できます。 この場合、次の要素を使用します。









実装



エンドポイント(エンドポイント)、ルーター(ルーター)、JSONパーサー(JSONハンドラー)などのコンポーネントを実装したい。 次に、結果をHerokuにデプロイし、着信リクエストを処理できるようにします。 これをどのように達成できるかを見てみましょう。







アプリ



Elixirプロジェクトにスーパーバイザーが含まれていることを確認してください。 これを行うには、次のようなプロジェクトを作成します。







 mix new minimal_server --sup
      
      





mix.exsに以下が含まれていることを確認してください。







 def application do [ extra_applications: [:logger], mod: {MinimalServer.Application, []} ] end
      
      





ファイル lib/minimal_server/application.ex



を作成します







 defmodule MinimalServer.Application do use Application def start(_type, _args), do: Supervisor.start_link(children(), opts()) defp children do [] end defp opts do [ strategy: :one_for_one, name: MinimalServer.Supervisor ] end end
      
      





図書館



mix.exs



次のライブラリを指定する必要があります。







 defp deps do [ {:poison, "~> 4.0"}, {:plug, "~> 1.7"}, {:cowboy, "~> 2.5"}, {:plug_cowboy, "~> 2.0"} ] end
      
      





次に、依存関係をダウンロードしてコンパイルします。







 mix do deps.get, deps.compile, compile
      
      





エンドポイント



これで、サーバーへのエントリポイントを作成する準備がすべて整いました。 次の内容のlib/minimal_server/endpoint.ex



ファイルを作成しましょう。







 defmodule MinimalServer.Endpoint do use Plug.Router plug(:match) plug(Plug.Parsers, parsers: [:json], pass: ["application/json"], json_decoder: Poison ) plug(:dispatch) match _ do send_resp(conn, 404, "Requested page not found!") end end
      
      





Plug



モジュールには、使用するパスとHTTPメソッドに応じて着信要求をリダイレクトするPlug.Router



が含まれています。 リクエストを受け取ると、ルーターはmodule :match



を呼び出し、 match/2



関数で表されます。これは、対応するルートを見つける役割を果たし、その後、module :dispatch



にリダイレクトし、対応するコードを実行します。







APIをJSONに準拠させるため、 Plug.Parsers



を実装する必要があります。 指定された:json_decoder



を使用してapplication/json



リクエストを処理するため、リクエスト本文の分析に使用します。







その結果、すべてのリクエストに一致し、HTTP not found(404)コードで応答する「任意のリクエスト」という一時的なルートを作成しました。







ルーター



ルーターの実装は、アプリケーション作成の最後のステップです。 これは、作成したパイプライン全体の最後の要素です。Webブラウザーからの要求の受信から始まり、応答の形成で終わります。







ルーターは、クライアントからの着信要求を処理し、必要な形式でメッセージを送り返します( ファイルlib/minimal_server/router.ex



特定のコードを追加します-翻訳者のメモ
):







 defmodule MinimalServer.Router do use Plug.Router plug(:match) plug(:dispatch) get "/" do conn |> put_resp_content_type("application/json") |> send_resp(200, Poison.encode!(message())) end defp message do %{ response_type: "in_channel", text: "Hello from BOT :)" } end end
      
      





上記のRouter



モジュールでは、 GET



メソッドによって送信され、 /



ルートに沿って送信された場合にのみ、要求が処理されます。 Routerモジュールは、 application/json



およびbodyを含むContent-Type



ヘッダーで応答しapplication/json









 { "response_type": "in_channel", "text": "Hello from BOT :)" }
      
      





すべてをまとめる



ここで、 Endpoint



モジュールを変更してリクエストをルーターに転送し、 Application



を変更してEndpoint



モジュール自体を起動します。







最初の方法は、 MinimalServer.Endpoint



[ match _ do ... end



MinimalServer.Endpoint



前に追加することで実行できます。 翻訳者 ]文字列







 forward("/bot", to: MinimalServer.Router)
      
      





これにより、 /bot



へのすべてのリクエストがRouter



モジュールにルーティングされ、処理されます。







2番目の関数は、 child_spec/1



関数とchild_spec/1



関数をendpoint.ex



ファイルに追加することで実装できます。







 defmodule MinimalServer.Endpoint do # ... def child_spec(opts) do %{ id: __MODULE__, start: {__MODULE__, :start_link, [opts]} } end def start_link(_opts), do: Plug.Cowboy.http(__MODULE__, []) end
      
      





children/0



関数によって返されるリストにMinimalServer.Endpoint



を追加するapplication.ex



により、 MinimalServer.Endpoint



を変更できるようにMinimalServer.Endpoint



ました。







 defmodule MinimalServer.Application do # ... defp children do [ MinimalServer.Endpoint ] end end
      
      





サーバーを起動するには、次のようにします。







 mix run --no-halt
      
      





最後に、アドレスhttp:// localhost:4000 / botにアクセスして、メッセージを確認できます:)







展開









構成



ほとんどの場合、ローカル環境および操作のために、サーバーの構成は異なります。 したがって、これらのモードごとに個別の設定を入力する必要があります。 まず、 config.exs



config.exs



config.exs



を追加します。







 config :minimal_server, MinimalServer.Endpoint, port: 4000
      
      





この場合、アプリケーションがtest



prod



およびdev



モードで起動されると、これらの設定が変更されていなければポート4000を受け取ります。







翻訳者から

この時点で、元のテキストの作成者は、config.exsを変更して、モードごとに異なるオプションを使用する方法について言及するのを忘れていました。 これを行うには、 config/config.exs



最後の行にimport_config "#{Mix.env()}.exs"



;をconfig/config.exs



ます。 結果は次のようになります。







 use Mix.Config config :minimal_server, MinimalServer.Endpoint, port: 4000 import_config "#{Mix.env()}.exs"
      
      





その後、 config



ディレクトリにprod.exs



test.exs



dev.exs



各ファイルをprod.exs



test.exs



作成します。







 use Mix.Config
      
      





本番環境では、通常、ポート番号をハードに設定するのではなく、次のようなシステム環境変数に依存します。







 config :minimal_server, MinimalServer.Endpoint, port: "PORT" |> System.get_env() |> String.to_integer()
      
      





上記のテキストをconfig/prod.exs



最後に追加します-約
翻訳者







その後、固定値がローカルで使用され、運用操作では環境変数の構成が使用されます。







endpoint.ex



でこのスキームを実装してみましょう( start_link / 1関数を置き換える-トランスレーターコメント ):







 defmodule MinimalServer.Endpoint do # ... require Logger def start_link(_opts) do with {:ok, [port: port] = config} <- Application.fetch_env(:minimal_server, __MODULE__) do Logger.info("Starting server at http://localhost:#{port}/") Plug.Adapters.Cowboy2.http(__MODULE__, [], config) end end end
      
      





ヘロク



Herokuは、複雑なセットアップなしで最も簡単なワンクリック展開を提供します。 プロジェクトをデプロイするには、いくつかの簡単なファイルを準備し、リモートアプリケーションを作成する必要があります













Heroku CLIをインストールした後、次のように新しいアプリケーションを作成できます。







 $ heroku create minimal-server-habr Creating ⬢ minimal-server-habr... done https://minimal-server-habr.herokuapp.com/ | https://git.heroku.com/minimal-server-habr.git
      
      





次に、 Elixir Build Kitをアプリケーションに追加します。







 heroku buildpacks:set \ https://github.com/HashNuke/heroku-buildpack-elixir.git
      
      





この翻訳の時点で、ElixirとErlangの現在のバージョンは(プラスまたはマイナス)です。







 erlang_version=21.1 elixir_version=1.8.1
      
      





ビルドキット自体を構成するには、上記の行をelixir_buildpack.config



ファイルに追加します。







最後の手順は、Procfileを作成することです。これも非常に簡単です。







 web: mix run --no-halt
      
      





翻訳者注:Herokuでのビルド中のエラーを回避するには、アプリケーションで使用される環境変数の値を設定する必要があります。







 $ heroku config:set PORT=4000 Setting PORT and restarting ⬢ minimal-server-habr... done, v5 PORT: 4000
      
      





新しいファイルをコミットするとすぐに[ git-およそを使用して。 翻訳者 ]、Herokuにアップロードできます。







 $ git push heroku master Initializing repository, done. updating 'refs/heads/master' ...
      
      





そしてそれだけです! アプリケーションはhttps://minimal-server-habr.herokuapp.comで入手できます







まとめ



この時点で、フレームワークを使用せずに3( 4-およそTranslator )ライブラリのみを使用して、最も単純なJSON RESTful APIおよびHTTPサーバーをElixir実装する方法を既に理解しました。







単純なエンドポイントへのアクセスを提供する必要がある場合、Phoenixやその他のフレームワークに関係なく、Phoenixを毎回使用する必要はまったくありません。







plug



+ cowboy



とPhoenixの間に信頼性が高く、十分にテストされ、サポートされているフレームワークがないのはなぜですか? たぶん、単純なものを実装する必要は本当にないのでしょうか? たぶん、各企業は独自のライブラリを使用していますか? または、誰もがフェニックスまたは提示されたアプローチのいずれかを使用していますか?













リポジトリは、いつものように、私のGitHubで入手できます。








All Articles