Help us understand the problem. What is going on with this article?

ElixirでもPHP的に気軽なWebアプリ開発をしたい(Phoenixより薄いWebFW実現?)

fukuoka.ex/kokura.exのpiacereです
ご覧いただいて、ありがとうございます :bow:

Phoenixは、Rails同様、MVC※やルーティングによるWebアプリ構築を前提に置いているため、PHPのような気軽さでWebアプリを作るのに向いていないと思われがちです
※正確には、Phoenixのソレは、MVCのようで、MVCではありません

他にも、「Phoenixを使わず、薄いWebサーバを使いたい」といった声を聞くことがありますが、よくよく聞いてみると、ステータスコードをキメ細かく調整したり、サーバプロセスを自前で起動したい等の本来的な薄いWebサーバを必要としている訳では無く、「MVCを使いたくない」「ルーティングを書きたくない」といったレベルの要望だったりすることも多いです

そこで、Phoenixのルーティングやリクエストハンドラーを司る「Plug」の柔軟性を用いれば、PHPと同様の気軽さ…つまり「ロジック入りhtmlファイルを置いたパスにエンドポイントが作られる」という形式でWebアプリ開発することもできる … ということを実感していただくためにコラムを書きました

本コラムの検証環境

本コラムは、以下環境で検証しています(Windowsで実施していますが、Linuxやmacでも動作する想定です)

なおPhoenixは、1.3系でも動作します(ElixirもPhoenixのバージョンに準じた古いものでも大丈夫です)

事前準備:Phoenix PJを作成する

まずPhoenix PJを作成し、Phoenixを起動します

mix phx.new basic --no-ecto
…
Fetch and install dependencies? [Yn] 【Yを入力してEnter】
cd basic
iex -S mix phx.server

なおチョイ技として、上記Yで走るmix deps.getとnpm installのうち、npm installが遅いので、コンソールを2枚立てて、裏で走らせると、構築を待たずに先に進むこともできます

1枚目のコンソール
mix phx.new basic --no-ecto
…
Fetch and install dependencies? [Yn] 【Nを入力してEnter】
cd basic
mix deps.get
iex -S mix phx.server
2枚目のコンソール
cd 【上記Phoenix PJを作った元のフォルダ】
cd basic/asset
npm install

ブラウザで「http://localhost:4000」にアクセスすると、Phoenixで作られたデフォルトのWebページが見れます
image.png

PHPのような気軽さでWebアプリを作るには?

Phoenixが前提としている「特定MVCへのルーティング」をhtml.eexファイル名へと自動マッピングし、mix phx.newで生成されたコントローラがデフォルトで素通ししていないGETパラメータを素通しすればOKです

なお、html.eexファイル名へのマッピング時、複数階層のフォルダもマッピング可能とすることで、サブフォルダ配下のhtml.eexファイルにも気軽にアクセスできるようになります

手順①:html.eexの表示をルーティング不要に

まずはルーティングで、「*path_」というワイルドカード指定をすることで、多階層のURLパスを「path_」パラメータで取得できるようになります

「path_」パラメータには、URLに指定されたフォルダ階層が、リストで入ってきます(たとえば、abc/defというパスであれば、[ "abc", "def" ]という感じで)

lib/basic_web/router.ex
defmodule BasicWeb.Router do

  scope "/", BasicWeb do
    pipe_through :browser

#    get "/", PageController, :index  # <-- remove here
    get "/*path_", PageController, :index  # <-- add here

手順②:html.eexの複数階層フォルダ指定可能に

render()の第2引数に指定するパスは、デフォルトだと複数階層を指定できないので、Viewにワイルドカード的なパスのパターン指定を追加すれば、複数階層を指定可能にできます

lib/basic_web.ex
defmodule BasicWeb do

  def view do
    quote do
      use Phoenix.View,
        pattern: "**/*",  # <-- add here
        root: "lib/basic_web/templates",
        namespace: BasicWeb, 

手順③:パスの自動マッピング、GETパラメータの素通し

PageControllerで、「path_」パラメータのフォルダ階層リストを、html.eexのパスにマッピングします

また、mix phx.newで生成されたコントローラが「_params」という感じでアンダースコアで未使用にしているので、これを解除し、renderの第3引数に渡すことで、GETパラメータを素通しさせます

lib/basic_web/controllers/page_controller.ex
defmodule BasicWeb.PageController do
  use BasicWeb, :controller

  def index( conn, params ) do
    template = if params[ "path_" ] == nil, do: "index.html", else: Path.join( params[ "path_" ] ) <> ".html"
    render( conn, template, params: params )
  end
end

手順④:html.eexページを追加する

1)templates/page直下にhtml.eex追加

これで、page配下にhtml.eexを追加するだけで、新たなページが追加可能となったので、追加してみます

lib/basic_web/templates/page/another.html.eex
<h1>This is another page</h1>

<%= inspect( System.build_info() ) %>
<hr>
<%= inspect( @params ) %>

ここまでが終わったら、ブラウザで「http://localhost:4000/abc/def?abc=xyz123」にアクセスすると、以下のような結果が表示されることを確認して、準備完了です
image.png

これで、ルーティングやMVCを追加せずとも、PHPのように、新たなページ追加やGETパラメータ処理できるようになりました

2)templates/page配下のサブフォルダ下にhtml.eex追加

pageフォルダ配下にフォルダ階層を掘って、そこにhtml.eexを配置しても動きます

「abc」というフォルダを掘り、「def.html.eex」というWebテンプレートを追加します

lib/basic_web/templates/page/abc/def.html.eex
<h1>I'm def page</h1>

<%= inspect( @params ) %>

ブラウザで「http://localhost:4000/abc/def」にアクセスすると、以下のような結果が表示されます(「path_」パラメータにフォルダ階層がリストで入っていることも確認できます)
image.png

3)GETフォーム処理も気軽に書く

GETパラメータが通るようになっているので、formでフォーム処理も気軽に書けます

checkboxのような複数値を取るタイプには、nameの末尾に「[]」を置く点が、忘れてはならないポイントです

lib/basic_web/templates/page/abc/form.html.eex
<h1>I'm form page</h1>

<form method="GET" action="/abc/def">

<p>
メモ:
<input name="memo" type="text">
</p>

<p>
好きな言語:
<input name="language[]" type="checkbox" value="Elixir">Elixir
<input name="language[]" type="checkbox" value="Rust">Rust
<input name="language[]" type="checkbox" value="Julia">Julia
</p>

<p>
年代:
<select name="age">
  <option value="10">10代
  <option value="20">20代
  <option value="30">30代
  <option value="30">40代
  <option value="50">50代
  <option value="60">60代
  <option value="70">70代以上
</select>
</p>

<input type="submit" value="送信">

</form>

ブラウザで「http://localhost:4000/abc/form」にアクセスすると、以下のような結果が表示されます
image.png

「送信」ボタンを押下すると、入力されたパラメータが表示されますが、def.html.eexでやっているように、@ paramsの中身を使ってフォーム処理を行うことができます

checkboxは、選択したものが、リストで入ってきます
image.png

4)POSTフォーム処理も気軽に書く

POSTパラメータによるフォーム処理に対応するには、ルーティングにPOSTの分も書きます

lib/basic_web/router.ex
defmodule BasicWeb.Router do

  scope "/", BasicWeb do

    post "/*path_", PageController, :index  # <-- add here

formのmethodをPOSTに変更します

lib/basic_web/templates/page/abc/form.html.eex
<h1>I'm form page</h1>

<form method="POST" action="/abc/def">
              ^-- modify here
…

ブラウザで「http://localhost:4000/abc/form」にアクセスし、「送信」ボタンを押下すると、GET同様、POSTでも入力されたパラメータが表示されるようになります(GETのときはURLにパラメータがあったのに対し、POSTでは無くなっています)
image.png

終わり

Phoenixで、PHPみたいに気軽なWebアプリ開発をする手順を紹介しました

Phoenixは、ルーティングとMVCを前提にしていますが、Plugの機能とコントローラでのパラメータ処理を併用すれば、このような気軽さを導入することもできます

無論、ルーティングやMVCは、理由があって採用されている面もあるので、そのメリット/デメリットはちゃんと学んだり、理解しつつ、一方で、このテクニックを使って、簡単なWebアプリ構築もお楽しみください

なお、Elixirサーバサイドでリアルタイムフロントが書ける「LiveView」においても、この気軽さを導入するコラム書いていますので、ご参考にどうぞ

p.s.このコラムが、面白かったり、役に立ったら…

image.pngimage.png にて、どうぞ応援よろしくお願いします:bow:

piacerex
福岡でプログラマしながらIT商社とIT企業を経営してます。Elixir/Kerasをよく使う。Elixirコミュ#fukuokaex、福岡理学部#FukuokaScienceを主催。プログラマ歴36年/XPer歴19年/デジタルマーケッター/経営者/CTO/技術顧問数社。 シボと重力子放射線射出装置は別腹(^^)
https://github.com/piacerex
karabiner
主にシステム開発・アプリ開発・ Webサイト制作を行う会社です
http://www.karabiner.tech/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした