Hello World web app in Elixir, part 3 - Phoenix
This is a continuation of Hello World web app in Elixir, part 2 - Plug.
Phoenix
Phoenix is the Elixir web framework of choice.
Init
I’m initializing the app with Phoenix’s new
task. I opt out of Ecto because I won’t be using a database, and Brunch, because I won’t have any front-end parts.
1
$ mix phoenix.new hello_world --no-brunch --no-ecto
Config
I’m changing the port in the development config file:
1
2
3
# config/dev.exs
config :hello_world, HelloWorld.Endpoint,
http: [port: 8003]
HelloWorld.Router
I’m deleting the default routes and adding my own:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# web/router.ex
defmodule HelloWorld.Router do
use HelloWorld.Web, :router
scope "/", HelloWorld do
get "/hello", HelloWorldController, :hello
get "/hello/:name", HelloWorldController, :hello
get "/*path", HelloWorldController, :goodbye
post "/*path", HelloWorldController, :goodbye
put "/*path", HelloWorldController, :goodbye
patch "/*path", HelloWorldController, :goodbye
delete "/*path", HelloWorldController, :goodbye
end
end
There is no way to match every method at once (and that’s on purpose). I have to add routes for each method separately.
HelloWorld.HelloWorldController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# web/controllers/hello_world_controller.ex
defmodule HelloWorld.HelloWorldController do
use HelloWorld.Web, :controller
def hello(conn, params) do
name = params["name"] || "World"
body = "Hello, #{String.capitalize(name)}!"
conn
|> put_status(200)
|> text(body)
end
def goodbye(conn, _params) do
body = "Goodbye!"
conn
|> put_status(404)
|> text(body)
end
end
put_status/2
is Plug’s function for setting the response status without sending a response yet. text/2
is a Phoenix’s function for responding with plain text. I could have also written it exactly like in part 2:
1
2
3
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, body)
I don’t have to do anything extra to get logging or live reloading - those come with Phoenix by default. Hooray!
Running the app
I’m starting the app with mix phoenix.server
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ curl -w "\n%{http_code}\n" http://localhost:8003/hello
Hello, World!
200
$ curl -w "\n%{http_code}\n" http://localhost:8003/hello/moon
Hello, Moon!
200
$ curl -X POST -w "\n%{http_code}\n" http://localhost:8003/hello
Goodbye!
404
$ curl -w "\n%{http_code}\n" http://localhost:8003/
Goodbye!
404
If this was a real project, I should probably also delete all that unneeded stuff that mix phoenix.new
generated. Not to mention all of the tests I should have written… let’s just skip that for the sake of the length of this post.
Conclusion
Using only Cowboy to write a web app was hard for me. The official documentation is in Erlang. The examples found on the web are mostly for Cowboy v.1 and I wanted to try out the v.2 prelease, and by doing so I only made the whole process more difficult. Remix doesn’t work really well with Cowboy’s routing - live reloading didn’t work for me in that case. I wouldn’t want to develop a bigger bare Cowboy app anytime soon.
Using Plug was comfortable enough. It seems like a good fit for microservices that wouldn’t have any front-end parts.
I don’t have any opinions on Phoenix yet because I only spent about 30 minutes with it so far. I’m really glad I started with exploring Cowboy and Plug first. Phoenix does not feel like magic from the very beginning (unlike Rails, which I started learning without a solid foundation in Ruby, not to mention any knowledge of Rack). I’m looking forward to developing something more complicated with Phoenix soon.