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.exsconfig.exsconfig.exsを追加します。


 config :minimal_server, MinimalServer.Endpoint, port: 4000 

この場合、アプリケーションがtestprodおよび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.exstest.exsdev.exs各ファイルをprod.exstest.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で入手できます。



Source: https://habr.com/ru/post/J444554/


All Articles