Building a Web App with Elixir & Phoenix — Part 1

April 19, 2018


This guide assumes you are running Phoenix 1.3

If you are building your first Web Application you should take a look at Elixir & Phoenix Framework. Elixir is built upon Erlang/OTP which is known for it’s fault tolerence and high concurrency. Erlang’s reliability and fault tolerance has given itself a legandary nine “9”s uptime (that is 99.9999999% uptime!). The Erlang/OTP standard also powers the majority of telecom infrastructures around the world, so you can be sure it is of amazing pedigree.

Erlang can be hard to learn, so Elixir was created to make Erlang/OTP more approachable.

Mix Tools are great, but you should try to wire up your own

I’ve just started picking up Elixir over the last days and found that although there are many great guides on the Elixir language, there isn’t one where it clearly describes how an Elixir application evolves.

This guide is meant to help you understand how the parts fit together and more importantly how an application evolves in stages:

Basic Elixir app --> 
Elixir app + data persistence -->
Elixir app + data persistence + talking to outside world 

Hopefully manually wiring up interfaces will help you figure out how the parts work together. Trust me by the time you completed these 3 parts you’ll ask yourself why more applications were not designed like this. Disclaimer

I’m still new to Elixir. This guide may be entirely rewritten as I understand best practices of Elixir. You should ideally know how Elixir works. Just getting through the started guide will be sufficient so you know how the syntax works and what mix tools are.

Start a new, vanilla Elixir project.

mix new todoapp --module TodoApp

This creates a new directory called todoapp with the basic structure of an Elixir application. Passing the --module flag lets you name the application.

Unlike other web frameworks, where it dictates your application structure, Elixir does not. Notice it make no assumptions about what you are building. No routes, no models, nothing. Just bare minimum for Elixir to compile the application.

> mix compile
Compiling 1 file (.ex)
Generated todoapp app

What about Phoenix?

You can’t avoid a conversation about Phoenix when talking about Elixir. Phoenix is a web framework for Elixir but it is not “AN APPLICATION” per say. Phoenix adds the functionality and interfaces for your application to connect with the outside world. We will come back to Phoenix in part 3 of the guide.

Phoenix is not your application! — by the Elixir community

Let’s start creating the models. Create a file in lib/ and call it models.ex and inside it insert,

defmodule Todo do
  defstruct task: "Buy milk", completed: false

In Elixir, struct constructs provide “compile-time checks and default values”, making it a suitable construct for defining models and their property types. It is probably the closest equivalent to an Object Oriented structure. Open up the Elixir console iex by typing iex in your console. Try,

iex(1)> c("lib/models.ex")
iex(2)> todo1 = %Todo{ task: "Get fruits", completed: true}
%Todo{completed: true, task: "Get fruits"}

Essentially the struct allows you to define model schemas. Try to create a new todo with a key that does not exist (for example: category) and see what happens. Adding Data Persistence

Not very helpful if you can’t store this somewhere correct? To store data, we need to talk to a database. You can do this with Ecto andPostgrex. Ecto handles the mapping between Elixir and common database schemas, while Postgrex is an adaptor that actually passes instructions between your Elixir app and Postgres database.

So while your current Todo struct was useful for manipulating within the context of an Elixir app, it is not useful for the outside world. We need to update the code for models.ex.

First, let’s try to add Ecto to our project. Go to mix.ex and update the dependencies,

defp deps do   
   {:ecto, "~> 2.0"},    
   {:postgrex, "~> 0.11"}

Next, install the dependencies using mix dep.get, which will output something similar to,

Resolving Hex dependencies...
Dependency resolution completed:
connection 1.0.4
db_connection 1.1.3
decimal 1.5.0
ecto 2.2.10
poolboy 1.5.1
postgrex 0.13.5
* Getting ecto (Hex package)
* Getting postgrex (Hex package)
* Getting connection (Hex package)
* Getting db_connection (Hex package)
* Getting decimal (Hex package)
* Getting poolboy (Hex package)

Let’s attempt to configure the database

mix ecto.gen.repo -r TodoApp.Repo

This command will eventually have 3 important lines,

* creating lib/todo_app
* creating lib/todo_app/repo.ex
* updating config/config.exs

Open up repo.ex,

defmodule TodoApp.Repo do
  use Ecto.Repo, otp_app: :todoapp

This is the module that we will eventually use to talk to the database.

At the end of the previous command you may have also noticed these instructions,

Don't forget to add your new repo to your supervision tree (typically in lib/todoapp/application.ex):

supervisor(TodoApp.Repo, [])

And to add it to the list of ecto repositories in your configuration files (so Ecto tasks work as expected):

config :todoapp,
ecto_repos: [TodoApp.Repo]

If you are not familiar with Supervisors, you should read up the documentation on Elixir docs. Ecto needs to be started as a process within your supervisor tree.

# Modify todoapp.ex
defmodule TodoApp do
   use Application

      def start(_type, _args) do
      children = [
          {TodoApp.Repo, []}
      opts = [strategy: :one_for_one, name: TodoApp.Supervisor]
      Supervisor.start_link(children, opts)

# Modify mix.exs
def application do
      extra_applications: [:logger],
      mod: {TodoApp, []}

What this does is to trigger an application callback on TodoApp, which will in turn fire TodoApp.start/1, which starts TodoApp.Repo.

In config.exs, add this line as an additional configuration

config :todoapp, ecto_repos: [TodoApp.Repo]

Once you are done, run mix ecto.create to create the tables. You may run into trouble such as,

Compiling 4 files (.ex)
Generated todoapp app
** (Mix) The database for TodoApp.Repo couldn't be created: FATAL 28000 (invalid_authorization_specification): role "user" does not exist

In this case, open up config.exs and update your Postgres settings to allow you to create a database. Managing Postgres is outside the scope of this tutorial. If creation is successful you should see:

The database for TodoApp.Repo has been created

This concludes the first part of this guide. In the next part, we will set up your application to interact with the database you just created.

Like my content? Subscribe to receive tips on software engineering.
© Alvin Ng