0% found this document useful (0 votes)
340 views

Phoenix in Action v4

Uploaded by

rodrigo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
340 views

Phoenix in Action v4

Uploaded by

rodrigo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 156

MEAP Edition

Manning Early Access Program


Phoenix in Action
Version 4

Copyright 2018 Manning Publications

For more information on this and other Manning titles go to


www.manning.com

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
welcome
Thank you for purchasing the MEAP for Phoenix in Action. Elixir and Phoenix have
had an exciting past few years as the Elixir language and the Phoenix framework have
both started to take off and become legitimate players in the web development world.
There are now many companies that have staked their future business on the fact that
Phoenix sites built on Elixir are the future of web development.
The incredible processing speed of Elixir combined with its built-in support for
parallel and distributed programming (not to mention its fault-tolerance) really shine
when paired with the Phoenix framework. With Phoenix, web development with Elixir
is quick and enjoyable with speed of development and developer happiness major
selling points.
While Phoenix in Action will not teach you everything there is to know about
Elixir, it does have a chapter introducing you to (or refreshing you on) the basics of the
Elixir language. As more complex subjects come up during the book, there will likely
be a sidebar describing the new Elixir concept and definitely footnotes directing you to
where you can find more or deeper information regarding those features if you so
choose.
The flow of the chapters of Phoenix in Action will have you building a real-time
auction website step-by-step, first starting with business logic completely separate
from Phoenix and slowly adding more and more complex features and introducing
Phoenix-specific functionality along the way.
While Elixir and Phoenix are certainly production-ready, they are still relative
newcomers in the world of application development. Because of that, there are still
discussions around best practices and the most appropriate way to structure
applications and even where to introduce functionality. One of the best things about
Phoenix is that it stays out of your way, keeping most of its opinions to itself. But the
other side of that coin is that there can be many competing opinions. This book will
have its own opinion regarding how to structure our application, but there are other
ways to do it that are no less correct. But Phoenix in Action will encourage you to
make Phoenix only a single boundary to your real underlying application logic.
I'm excited about Elixir and Phoenix and what it will mean for the future of
application development, specifically for the web. I hope that you join me in this
excitement and provide feedback and comments during the development of Phoenix in
Action. Your involvement will be essential while I continue writing this book, so
please don't be shy in your interactions with me.

Many thanks,
—Geoffrey Lessel
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
brief contents
PART 1: AN INTRODUCTION
1 Ride the Phoenix
2 Intro to Elixir
3 A Little Phoenix Overview
PART 2: HE BASICS
4 Phoenix is Not Your Application—Just a Boundary
5 Elixir Application Structure
6 Bring in Phoenix
7 Being Persistent with a Database
8 Changes Are Coming
9 Transforming Data In Your Browser
10 Plugs, Assigns, and Dealing With Users
11 Accepting Auction Bids and Associating Records
PART 3: GETTING ADVANCED
12 Building an API
13 Real-time updates with channels
14 Testing

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
1

This chapter covers:



Ride the Phoenix

What Phoenix is and the benefits it provides over its alternatives


1
• The power of the Elixir programming language
• A brief overview of the differences between object-oriented and functional programming
• Some of the potential drawbacks to using Phoenix and Elixir

In this chapter, you will be introduced to the Elixir programming language and the
Phoenix web framework. We will be taking a look at the main advantages and
disadvantages a language and framework like Elixir and Phoenix provides. By the
end of the chapter, you’ll have a good overview of the technologies, why they
exist, and you’ll be ready to jump into learning the details and creating your own
web applications.

1.1 Along Comes Phoenix


While people have been creating websites for decades now, the tools they use to
create them have changed. In the early days, developers used simple text editors on
their computers to type out all the HTML needed in order to hyperlink one page to
another on their website. But once interactivity with the user was desired, things
got complicated. How can you create an e-commerce site with plain HTML? How
can you get information from a central database and display pages dynamically?
What if you wanted to display personalized information for every user that visited?
All these questions and more have been answered differently as time marched on.
We’ve gone from Perl scripts to PHP to Python, Java, C# and Ruby (not
necessarily in that order and leaving out many other languages). These languages
and others allowed the server to respond dynamically to information given to it via

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
2

a user’s interaction with the web site. Figure 1 shows how much more complex a
dynamic website may be over a static one.
Figure 1.1. Static websites vs. dynamic websites that frameworks help provide.

Arguably the biggest impact on the open-source web in the 2000’s was the release
and adoption of Ruby on Rails—a web framework written on the Ruby
programming language. This allowed developers to quickly and somewhat easily
get a dynamic web site up and running in very little time. The famous example
from that time was creating a blogging engine in 15 minutes. It allowed developers
great productivity and "Web 2.0" exploded.
From Ruby on Rails, many new web frameworks attempted to match or outdo
Ruby on Rails in terms of features and developer happiness. There became a go-to
web framework for each major programming language. In that vein Phoenix was
born.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
3

Other popular web frameworks

Language Framework
Elixir Phoenix
Ruby Ruby on Rails, Sinatra
Python Flask, Django
PHP Laravel, Symfony
Java Spring, Ninja
Javascript Meteor, Express, Sails
C# Nancy, ASP.NET Boilerplate
Perl Mojo, Catalyst

1.1.1 What is Phoenix?


Phoenix is a web framework that attempts (and, in my opinion, succeeds in) to help
the creation and maintenance of dynamic websites much simpler. Phoenix does not
attempt to copy the big player in this space: Ruby on Rails. Phoenix is built on top
of the Elixir programming language (which is a functional language) while Ruby is
an Object Oriented programming language (we’ll get into the details of the
differences later in this chapter). While Phoenix has best practices for structuring
and maintaining your application, it is not as dogmatic about it as Ruby on Rails
and other frameworks are — giving you flexibility to write your application how
you see fit.
Phoenix goes beyond many web frameworks as well. For example, Phoenix has the
concept of Channels built-in. Channels allow for "soft-realtime" features to be
easily added to applications. We’ll cover the topic of Channels further in-depth in
later chapters, but this is what allows you have chat applications, instant push
updates to thousands of simultaneous users, and page updates for the user without a
full-page refresh. While these kinds of features are difficult to add in other
languages and frameworks, it borders on trivial for Phoenix applications. Whole
books can be written about how to get these features into web applications using
other web frameworks (or rolling your own), but we’ll be adding them to our
application in just a few chapters.

1.2 Elixir And Phoenix Versus the Alternatives


This chapter is not intended to be a bullet-point list of things that Phoenix and
Elixir do well over other alternatives, but in order to introduce you to the power of
Phoenix and Elixir, here are a few of the exciting things that Phoenix offers and
that we will be covering in this book.
1.2.1 Real-time Communication
What can you do with real-time communication? Well, any time you want to push
information to many users simultaneously, you’ll need some solution for that. That
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
4

could be with a chat application where users can send and receive chat messages to
thousands of other users and you need to keep each client up-to-date when another
client’s user submits a new message. It could be something more complex like an
auction site that wants to provide users visiting the auction item’s page up-to-the
second information regarding the state of the bids. Maybe it’s a workplace
collaboration site where users are sharing files and even working on the same file
simultaneously. Or perhaps there is a real-time multiplayer game server that you
want to build and you need to ensure that all players have the same information at
the same time. There are many different situations in which real-time channels are
necessary, and many more in which it would be beneficial. Figure 7 illustrates a
simple situation in which bandwidth can be saved and the user experience
improved with pushing data to the user instead of requiring the user to pull the data
from the server.
Figure 1.2. Traditional "pull" refreshed require the user to initiate the request and the server to
return the entire web page again.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
5

Figure 1.3. A "Push" requests originates from the server and "pushes" new information to the
user which is typically only that which changed, greatly reducing payload and speeding up page
rendering.

Elixir can spawn and efficiently handle hundreds of thousands of processes without
blinking an eye (we go into a bit more detail in the section about Elixir below).
You’ve also read briefly about Phoenix’s concept of channels which allow real-
time communication. Phoenix actually spawns each channel into its own process so
that no one process can damage or take down any of the others — they are
beautifully isolated.
Using these processes and a channels, Phoenix can handle a couple hundred
thousand connections on a single server! Granted, kudos to you if your web
application ever has hundreds of thousands of simultaneous users wanting to
communicate in real time—but that gives you an idea of the power of Phoenix and
Channels running within processes.
We’ll get more into Channels (and build some into our application) in later
chapters.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
6

1.2.2 Background Computation


There will be times during your time in development that you’ll want to do a long-
running computation or process but don’t want to keep the user from interacting
with your software whether that’s on the web or locally with some user interface.
For example, a user of a digital product e-commerce site may want to purchase a
product that is customized and then can be downloaded. Once the user finalizes the
purchase, you don’t want to require the user to wait on that page until the
personalization process is complete. Instead, you’d like for them to continue to
browse your store or set up their profile. This is a simple scenario in where
background computation can play a role.
Figure 1.4. Background processes can help do complex work without holding up the main
responses to the user.

If your application needs to do any more than a small amount of computation in the
background (normally asynchronously), then it is a perfect fit for something built
on top of Elixir like Phoenix. It is trivially easy to kick off background,
asynchronous processes with Elixir.
This fits in perfectly with the real-time communication features of Phoenix. Once
the long-running process is complete, the server could send a message through the
Channel to the user’s client that the process is complete and either display the
results directly on the client or provide a link or further instructions to retrieve the
results at a later time.
1.2.3 Low Hardware Requirements / Low-cost Scaling
If you look at any hosting provider’s offerings, you’ll notice that most of the time,

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
7

adding more CPU power/cores costs less than adding more RAM. This fits
perfectly with the way Elixir works. Elixir automatically utilizes all the different
CPU cores available to it and takes up a relatively very small amount of RAM in
order to run. Compare this to a web framework and language like Ruby on Rails
which is RAM hungry.
Other web frameworks built on differing programming languages CAN scale, but if
you are looking for a low-cost way to scale quickly, then Elixir and Phoenix would
be a good choice. Pinterest explains in a blog post 1 that they moved one of their
systems from Java to Elixir.
So, we like Elixir and have seen some pretty big wins with it. The system that
manages rate limits for both the Pinterest API and Ads API is built in Elixir. Its 50
percent response time is around 500 microseconds with a 90 percent response time
of 800 microseconds. Yes, microseconds.
We’ve also seen an improvement in code clarity. We’re converting our
notifications system from Java to Elixir. The Java version used an Actor system
and weighed in at around 10,000 lines of code. The new Elixir system has shrunk
this to around 1000 lines. The Elixir based system is also faster and more
consistent than the Java one and runs on half the number of servers.
1.2.4 It’s Not All Roses
While the Elixir language and the Phoenix framework are awesome and are usually
what I reach for when starting new projects, it is not always the de-facto best
choice for the job. There are some areas in which Elixir doesn’t do as good a job as
a different alternative.
• Time to Productivity: If you are already productive in a different web framework
using a different programming language, it may be hard to justify the cost of
getting up to speed in something new like Elixir. If you are just getting started in
development, one consideration is how long it will take you to become productive
in your new chosen language. Some people I’ve spoken to believe it is harder to
learn functional programming than Object-oriented programming while others
swear it’s the other way around. Regardless, I believe that Elixir and Phoenix offer
enough reasons for you to take the plunge and learn the language regardless of
your past experience levels.
• Numbers: Elixir isn’t a number-crunching powerhouse. It will never match the
pure computational speed of something lower level like C or C++. I’d even go so
far to say that if you are looking to primarily crunch large numbers, even Python is
a better choice. Elixir can do it and do it well, but it won’t win in a head-to-head
competition in this area.
• Community: While the community behind Elixir, Phoenix, and Erlang is very
helpful and enthusiastic, it is not as large as a community for something like Ruby,
1
medium.com/@Pinterest_Engineering/introducing-new-open-source-tools-for-the-elixir-community-2f7bb0bb7d8c
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
8

Python, Java, or even PHP. Those languages have a deeper and longer history in
the web application world and it might be easier to find help with your project in
one of those worlds. However, more and more meetups, conferences, blogs, jobs,
etc. are arriving all the time for Elixir and I believe the future will only hold great
things for the Elixir community.
• Packages: Going along with the above comment regarding the size and age of the
community surrounding Elixir versus other languages, the amount of open-source
packages available to use in your project is smaller. As of the time of this writing,
there are currently just under 4,500 packages available on hex.pm, the package
manager source for Elixir. Contrast that to rubygems which has over 8,500
packages and PyPI (the Python Package Index) which has over 109,000. While it
may be harder to find something that does exactly what you used in previously
programming languages, more packages are being built all the time. It also means
there is space for YOU to create a new helpful package and help grow the
community.
• Deploying: In the original draft of the table of contents of this book, a chapter
regarding deploying your application was discussed. However, this is an area that
is still, in all honesty, in need of a single, "best" solution. Deploying an Elixir
application (including ones that utilize the Phoenix web framework) is pretty
tricky and involves multiple steps. Beyond that, those steps are still not quite
clearly defined nor have mature tools to help in the process. We’ll provide
resources later on in the book that will give you some guidance on how to learn
about deploying your application, but it isn’t exactly easy at the moment.
Phoenix provides a lot of things that help you add normally-complex features to
your web applications but it will not be the foundation of your application. While it
may be strange to read that in a book specifically about Phoenix, the truth is that
Phoenix derives its powers from the amazing Elixir programming language.

1.3 The Power of Elixir


Elixir is a dynamic, functional language designed for building scalable and
maintainable applications.

Elixir leverages the Erlang VM, known for running low-latency, distributed and
fault-tolerant systems, while also being successfully used in web development
and the embedded software domain.

-- http://elixir-lang.org

Erlang and WhatsApp


There is a great story around Erlang and the popular messaging app WhatsApp which was
acquired by Facebook for $19 billion in 2014. When it was acquired, it had 450 million users
sending over 70 million Erlang messages per second. If WhatsApp had been built on a
programming language other than Erlang, it likely would have had a huge engineering staff.
However, since the application was written in Erlang and Erlang provides so many benefits for

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
9

real-time messaging applications, the engineering team at the time of acquisition was made
up of only 35 people. Your application may not ever have 450 million users sending 70 million
messages per second (well over that these days), why not utilize the technology that would
allow you to easily do so if required?

1.3.1 Scalability
One of the amazing things about Elixir is its scalability. Elixir has the idea of
processes running on your machine. These aren’t processes like you may have
thought of them in the past — they aren’t threads. Elixir processes are extremely
light-weight (the default initial size is 233 words or 0.5kb) and run independent of
all the other running processes. We will be building a Phoenix application through
the course of this book and it will not be surprising to find that thousands of
concurrent processes will be running on your machine in order to allow our
application to run. These processes are FAST, independent of each other, have
unshared memory, and can easily send and receive messages to other processes on
distributed nodes (different machines potentially in different parts of the world).
1.3.2 Supervision trees
Elixir applications (including Phoenix apps and our own application) have
Supervisors and Workers. The Supervisors monitor the Workers and ensure that if
they go down for one reason or another, they are started right back up. This
provides an amazing backbone of fault-tolerance without much work on our part.
We can configure how we’d like our Supervisors to handle their Workers if
something does happen to them including shutting down and restarting any sibling
workers. Beyond that, Supervisors can supervise other Supervisors! The
supervision tree can get pretty large and complex but this complexity does not
necessarily mean our application is harder to comprehend.
Figure 1.5. Supervisors and workers

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
10

Figures 2, 3, and 4 are true visualizations of a real-life application developed by a


friend of mine. This application is constantly running in the background to find
scheduling conflicts for an organization’s physical assets like rooms, buildings,
projectors, chairs, and the like. Each supervisor handles a group of rooms. When a
request comes in, each supervisor gets a request for it to ask each of the rooms it
supervises whether there are any scheduling conflicts. If any of the children
processes has any trouble and crashes for some reason, the supervisor notices and
starts it right back up.
These figures can give you an idea of how many processes can be spawned during
the running of a moderately complex application.
Figure 1.6. Each circle in this diagram is a real Elixir Process. Supervisors can supervise other
Supervisors, which in turn supervise Workers.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
11

Figure 1.7. The Process tree can continue to grow as your application runs.

Figure 1.8. Soon your application can spawn thousands of Workers, each isolated from the
other.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
12

The benefits of these Processes and Supervisors are many, but one in particular is
that it makes created distributed systems much easier than previously possible with
other languages. You can deploy your code to multiple servers in multiple areas of
the world (or in the same room) and have them communicate with each other. Need
more power? You can bring up another server node and your previous nodes can
communicate with the new node with minimal configuration, passing off some of
the required work as it sees fit.
1.3.3 Erlang VM
These particular features are available to us because the backbone of Elixir is
Erlang. Erlang has been around for decades now, silently and dependently
providing services to many of the things you use on a daily basis. Erlang was
created with the telecommunications industry in mind. And what does a
telecommunication service require? High fault tolerance, distributability, live-
updating of software — things that a modern-day web application should also be
able to rely on. Elixir runs on top of the Erlang VM which is rock-solid and has
been for decades. You can even run Erlang functions and use Erlang modules
directly in your Elixir applications! While this book will not go into the details of
Erlang and its VM, there are plenty of resources available that cover Erlang.
1.3.4 Macro and metaprogramming support
While Elixir runs on the Erlang VM, it is itself written in Elixir. How is that
possible? It is another one of the great things about the Elixir language — macros.
Elixir is extensible via built-in support for macros which allow anyone to define
their own language features. You can build your own little language or DSL within
Elixir itself. As Figure 5 illustrates, 89% of the Elixir codebase is itself Elixir—the
rest is made up of Erlang and various shell files.
Figure 1.9. Breakdown of language types in Elixir’s source code (as of June 2017)

1.3.5 OTP
Finally, one feature of Elixir that cannot go unwritten is its ability to utilize OTP.
OTP stands for "Open Telecom Platform" but that name isn’t very relevant
anymore so you’ll almost always just see OTP. These are a set of functions,
modules, and standards that make using things such as Supervisors and Workers,
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
13

and the fault-tolerance that goes along with that possible. There are concepts such
as GenServer, GenStage, concurrency, distributed computation, load balancing,
and worker pools to just name a few. It’s been light-heartedly said that any
complex problem you are attempting to solve has likely already been solved in
OTP.
If half of Erlang’s greatness comes from its concurrency and distribution and
the other half comes from its error handling capabilities, then the OTP
framework is the third half of it.

-- http://learnyousomeerlang.com/what-is-otp

So with all that greatness backing Phoenix, what if you don’t know Elixir? That’s
OK. Chapter 2 will take you through the basics of the Elixir language and, if you
want to go even deeper, recommend some resources you can check out.

1.4 Functional vs OO Programming


To this point in history, I think it is fair to say that the majority of web applications
are built on object-oriented programming languages. Ruby, Python, Java, and C#
are all object-oriented and are widely used in web application development. In
recent releases, even historically procedural languages like PHP and Perl have been
gaining object-oriented features. And while the number of developers productively
using these languages remains high, there seems to be a recent shift away from the
notion that object-oriented programming is the best way forward and towards more
functional programming languages (such as Elixir, Haskell, Lisp, Clojure). Even
though most object-oriented programming languages are not prevented from
writing applications in a functional way, having a language that is strictly
functional from the beginning has its advantages.
1.4.1 Overview of Functional Programming
Functional programming is all about data transformation. Mutable (changeable)
data and changing state are avoided (and in some cases impossible). The reality is a
function which is passed the same parameters multiple times will return the same
answer every time. In purely functional code, nothing outside of that function will
be considered when the return value is computed. One of the results of this is that
return values of functions need to be captured in order to be used again — there is
no object holding onto its state.
Let’s suppose that we want to do some calculations regarding a race car and keep
track of things like what kind of tires it has, it’s speed, acceleration, etc. We could
group that information into an Elixir module that will not only defined the structure
of the data we desire, but also be a central place to hold all the functions regarding
a race car.
Let’s take a look in Listing 1.4 at what a race car module might look like in Elixir.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
14

Don’t worry too much about the syntax — we’ll cover that later. This may not be
the best example of using the features of the language to their fullest potential, but
it will give you an idea of the code syntax and structure.

Listing 1.1. An example RaceCar module in Elixir

defmodule RaceCar do
defstruct [:tires, :power, :acceleration, :speed]

def accelerate(%RaceCar{speed: speed, amount: amount} = racecar) do


Map.put(racecar, :speed, speed + amount)
end
end

ferrari_tires = [
%Tire{location: :front_right, kind: :racing},
%Tire{location: :front_left, kind: :racing},
%Tire{location: :back_right, kind: :racing},
%Tire{location: :back_left, kind: :racing}
]
ferrari = %RaceCar{tires: ferrari_tires,
power: %Engine{model: "FR223"},
acceleration: 60,
speed: 0}
ferrari.speed
# => 0
RaceCar.accelerate(ferrari)
# => 60
ferrari.speed
# => 0
new_ferrari = RaceCar.accelerate(ferrari)
new_ferrari.speed
# => 60
ferrari.speed
# => 0

Look carefully — our ferrari variable does not get changed when we pass it to
the RaceCar.accelerate/1 2 function. We can run that line 1,000 times and we’d
get the same return value every time: an updated structure of the ferrari with a
new speed. But remember, our original ferrari doesn’t change in memory. We
have to capture that return value in order to use it later. What this kind of
programming provides is an elimination of side effects. We can run our function at
any time and be confident that it will always return the same value for the same
input — regardless of time of day, "global state", what order functions were called
in, etc.

2
This syntax means the accelerate function inside the RaceCar module that has argument arity (the number of function
arguments) of 1
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
15

Eliminating side effects, i.e. changes in state that do not depend on the function
inputs, can make it much easier to understand and predict the behavior of a
program, which is one of the key motivations for the development of functional
programming.

-- https://en.wikipedia.org/wiki/Functional_programming#Coding_styles

In simple terms, object-oriented programming involves objects holding onto their


state (data) and providing methods to the outside world that allow them to access,
modify, or even delete that data. In contrast, Elixir modules don’t store state (data)
on their own—they simply provide functions that operate on the data passed to
them and return that data back to the caller. Figure 6 gives a simple visualization of
how Objects handle data vs how functional modules handle data.
Figure 1.10. Object-oriented programming generally involves an object that keeps track of its
own data (state). Methods are used to manipulate that internal state and retrieve it for other
uses.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
16

Figure 1.11. Functional programming generally involves having a module that contains
functions that act together for a purpose. The module holds no data (state) but only returns the
result of the function based on the data the user gives it.

In the world of object oriented programming, an object’s internal data or state is


open for many different things to mutate it during an operation. Because of the
often dynamic nature of object-oriented languages, a third-party package could
hook into your codebase and modify your data without you even knowing. In
contrast, when working with Phoenix, the data flows in one single line from the
user making the request to the requested page being displayed. And for each step
the data takes, you specify how that data is being passed along. The side effects are
therefore minimal (and most of the time eliminated entirely).

1.5 Summary
In this chapter you learned:
• Dynamic websites can be a tricky problem to solve. Web frameworks cam along
to help make the solution easy and quick to implement. Phoenix delivers on this
promise and can get your dynamic (or static) website online with minimal fuss.
• Much of the power of Phoenix comes from the Elixir langauge. Elixir runs on the
Erlang virtual machine (VM) so you could say that much of the power of Elixir
comes from the Erlang VM.
• There are strong benefits to writing a web application with Phoenix over other
alternatives including fault-tolerance, speed, concurrency, real-time
communication, distribution, and potential hardware cost savings.
• A few key differences between object-oriented programming in languages such as
Ruby vs functional programming in a language like Elixir. While OO languages
try to model the domain in real-world object terms that abstract away the code
interface from the data that object holds, functional programs treat the data as
king. All the code of a program is built around explicitly manipulating the data in
an immutable way by passing the result of one function to the input of another.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
17

• Some of the areas in which Elixir/Phoenix may not be the best choice for your
particular application — like requirements for pure processing speed, number
crunching, huge communities, lots of readily-available packages, considering the
time it will take to become productive, and the current difficulty of deployment.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
18

This chapter covers:


• The basics of the Elixir programming language
2
Intro to Elixir

• How to create a module


• Using built-in tools to help you work smarter

Now that you’ve read a bit about the benefits Phoenix can bring to your web
application development, you’ll need to know Elixir to use it. Phoenix is a web
"framework" that is built on top of the Elixir language (which, as you’ve seen in
previous chapters, is itself built on the Erlang VM known as BEAM). So what if
you don’t know Elixir?
In this chapter you will get up to speed on Elixir so that you can start learning the
language and how to write in it. If you already know Elixir, it is likely you can skip
this chapter entirely and move on. If you don’t know Elixir or need a refresher, this
chapter will cover just enough Elixir to get you going. I’ll point you to more
resources at the end of the chapter if you’d like to dive deeper into the language
and all its features.

2.1 The Basics


Once you have installed Elixir, you’ll have executables newly available to you
including iex. For a lot of this chapter (and a few past this), we will be inside
an iex session. IEx stands for "Interactive Elixir" and it is a REPL (Read-Eval-
Print Loop) for Elixir. A REPL takes user input, evaluates it, prints it out back to
the user, and loops back around to take user input again. Figure 1 illustrates this
loop.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
19

Figure 2.1. A REPL takes user input, evaluates it, prints it out back to the user, and loops back
around to take user input again

IEx is basically going to act as our Elixir playground as we are getting started. But
don’t let that fool you — it is actually a pretty powerful tool even for the most
advanced Elixir users. Let’s fire it up and see what we get.
In order to start a new session, open up your terminal program and
type iex (or iex.bat in Windows). You’ll see something like:
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe]
[kernel-poll:false] [dtrace]

Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>

Note that there is a lot of debugging information displayed in the above and most
of those numbers and terms won’t matter to us during our usage of IEx. In fact,
some of it may look a little bit different on your computer. If it does, don’t worry
about it too much. The two most important things to take a look at are the
Erlang/OPT version (19 in my case) and the Elixir version (1.4.2) you are running.
If you ever are in need of assistance in online discussions, those two version
numbers will likely be important to help those who are assisting you.
Another thing to notice is that it provides you with two hints:
1. press Ctrl+C to exit
2. type h() ENTER for help

These are both pretty self-explanatory, but when the time comes to close

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
20

your iex session, press Ctrl+C on your keyboard. Once you do, you’ll see this:
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution

For now, don’t worry about those options other than (c)ontinue. If you
pressed Ctrl+C by accident or now regret your decision, you can press c to continue
your iex session. If you would indeed like to quit and move on to other things, just
press Ctrl+C a second time or a. Those will dump you back out into your terminal.
The second thing to notice is the h() for help. You can follow along with Listing
2.1 by tying h() in your IEx session now.

Listing 2.1. Getting help from an IEx session

iex(1)> h()
IEx.Helpers

Welcome to Interactive Elixir. You are currently seeing the documentation for
the module IEx.Helpers which provides many helpers to make Elixir's shell more
joyful to work with.

This message was triggered by invoking the helper h(), usually referred to as
h/0 (since it expects 0 arguments).

You can use the h/1 function to invoke the documentation for any Elixir module
or function:

iex> h Enum
iex> h Enum.map
iex> h Enum.reverse/1

You can also use the i/1 function to introspect any value you have in the
shell:

iex> i "hello"

There are many other helpers available:

• b/1 - prints callbacks info and docs for a given module


• c/1 - compiles a file into the current directory
• c/2 - compiles a file to the given path
• cd/1 - changes the current directory
• clear/0 - clears the screen
• flush/0 - flushes all messages sent to the shell
• h/0 - prints this help message
• h/1 - prints help for the given module, function or macro
• i/1 - prints information about the data type of any given
term
• import_file/1 - evaluates the given file in the shell's context
• l/1 - loads the given module's BEAM code
• ls/0 - lists the contents of the current directory

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
21

• ls/1 - lists the contents of the specified directory


• nl/2 - deploys local BEAM code to a list of nodes
• pid/1 - creates a PID from a string
• pid/3 - creates a PID with the 3 integer arguments passed
• pwd/0 - prints the current working directory
• r/1 - recompiles the given module's source file
• recompile/0 - recompiles the current project
• respawn/0 - respawns the current shell
• s/1 - prints spec information
• t/1 - prints type information
• v/0 - retrieves the last value from the history
• v/1 - retrieves the nth value from the history

Help for all of those functions can be consulted directly from the command line
using the h/1 helper itself. Try:

iex> h(v/0)

To learn more about IEx as a whole, type h(IEx).

Whoa, that’s quite a bit of text that was just spit out! But don’t get overwhelmed —
 all of it is very helpful. One of the great things about Elixir is its idea of
documentation being a first-class citizen along with your code. We’ll get into code
documentation in later chapters, but as a quick example, if you typed h(clear/0), it
would give you documentation on the clear/0 function. That documentation is
written just above the function declaration in the Elixir source code. The source
code itself has this documentation alongside the code that makes it run. Figure 2 is
a screen shot from the source code listing for clear/0. You can see that the lines
dedicated to documentation closely matches the lines of code for the function. This
is an example of a function with light documentation and the documentation is at
times extensive, sometimes covering dozens of lines with multiple built-in
examples. This makes reading Elixir source code files really easy. It also makes
discovering how to use new modules and functions really easy!

Figure 2.2. The source code AND built-in, in-line documentation for clear/0

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
22

2.1.1 Basic Types


Now that we know how to get help in and how to exit an iex session, let’s play
around with some of the basic building blocks of the Elixir language. There are
some basic types in Elixir that you will need to know. This table will only serve to
introduce the type names and an example of that type, but we will go into detail on
each of these types later on in this chapter.

Table 2.1. Basic Elixir types

Type Example(s)
Integer 34
Float 387.936
Boolean true / false
String "Phoenix in Action"
Charlist 'Phoenix in Action'
Atom :phoenix_in_action
List [34, 387.936, false]
Tuple {34, 387.936, false}
Map %{name: "Geoffrey", location: "Oceanside, CA"}

Since these are basic types in Elixir and we are not doing any manipulation of the
data in them, if we enter these in IEx—IEx will just echo back the result (which is
the data itself). You can follow along with Listing 2.2 by typing the same things in
your IEx session.
We will be covering each of this more in-depth in the rest of this chapter, so no
need to memorize them now.

Listing 2.2. listing name

iex(3)> 34
34
iex(4)> 387.936
387.936
iex(5)> true
true
iex(6)> "Phoenix in Action"
"Phoenix in Action"
iex(7)> 'Phoenix in Action'
'Phoenix in Action'
iex(8)> :phoenix_in_action
:phoenix_in_action
iex(9)> [34, 387.936, false]
[34, 387.936, false]
iex(10)> {34, 387.936, false}
{34, 387.936, false}

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
23

2.1.2 A Small Detour Into Functions


Before we get into the details of the basic types, let’s do a quick tour of functions
in Elixir. Why the detour? Well, some of the things we will do while explaining the
basic types will use functions so let’s explain those first.
There are two main types of functions in Elixir: named functions and anonymous
functions. Most of the time, you will write and use named functions but
anonymous functions are still very helpful.
NAMED FUNCTIONS
Named functions in Elixir are ALWAYS within the context or scope of a module.
A named function cannot exist outside of a module. You can think of a module as a
collection of functions that are grouped together for a purpose. For example, you
could group together functions dealing with the manufacturing of shirts in
a Factory.Shirt module. The reality is that there is nothing at all special with the
name of the module—the functions inside of it could be defined in any module in
your application and they would work the same. To help remember the structure of
a function call, you can remember MFA or "module-function-arguments". The first
thing you write is the module name, followed by the module’s function name, and
finally the arguments for that function. Figure 3 visually illustrates the different
pieces that make up a function call in Elixir.
Figure 2.3. The module-function-arguments structure

As Figure 3 illustrates, a named function is called by its name and you can provide
it arguments it expects:
iex(1)> Kernel.is_integer(3)
true

Here we’ve called the is_integer function inside the Kernel module.
iex(1)> Kernel.length([1, 2, 3])
3

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
24

And here we call the length function inside the Kernel module.
One thing to note is that Kernel functions are available in most situations without
explicitly typing Kernel. This makes these functions available to use almost
everywhere (we’ll discuss how you can make your module functions act in the
same way later in the book). For example, these two calls are the exact same as the
two above:
iex(1)> is_integer(3)
true

iex(2)> length([1, 2, 3])


3

There are also some special forms that are available to use. These include +, -
, *, /, ==, !=, etc., and there are quite a few of them. These special forms can be
used everywhere and are actually function calls. You can call them a bit differently
though thanks to some syntatic sugar. 3
iex(1)> 1 + 3
4

iex(2)> Kernel.+(1, 3)
4

Both of the above forms actually call directly to Erlang’s implementation of +. In


fact, you can also use Erlang’s functions directly at any time:
iex(3)> :erlang.+(1, 3)
4

The above syntax is special for Erlang and we will not be using it much during our
time in Elixir. If you’d like to explore the different Kernel functions available to
you, take a look at the source code for the Kernel module. Trust me, it’s not as
scary as it sounds. In fact, the vast majority of the file is made up of documentation
and examples.
ANONYMOUS FUNCTIONS
Anonymous functions are functions that are not called by a name. They can exist
outside of a module unlike named functions. You can bind them to a variable name
which you can use to call the function later on (with a bit different syntax). One
way to think about an anonymous function is as a simple (or complex) piece of
data transformation that you may or may not need to repeat.

3
This is a good example of "prefix notation" vs "infix notation". Kernel.+(1,3) is the normal prefix notation, but Elixir
provides 1 + 3 with infix notation. Simply put, infix notation has the function call between the two arguments. There are
not very many functions that have infix notation in Elixir and you will rarely write one of your own. But sometimes it’s
nice to know the correct term for things!
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
25

For example, suppose you are making sandwiches at a deli. You need to repeat the
same process over and over again. If you needed to write the sequence in code, you
could write out each step every time an order came in. Or, you could store the same
standard steps in a function and just use that function every time an order came in.
Then, it wouldn’t matter how many orders you received—your code can handle the
extra business. In psuedocode, it might look like Listing 2.TODO.

Listing 2.3. listing name

for each order received:


on a plate:
add bread
add mustard
add turkey
add cheese
add tomato
add lettuce
add bread
return plate to customer

That’s a lot of repeating ourselves by explicitly add ing every ingredient. Let’s take
these steps and slowly build an Elixir implementation using anonymous functions.
Figure 3 illustrates the pieces required to define an anonymous function.
Figure 2.4. Pieces of an anonymous function

The standard procedure inside on a plate: could be contained in a function. To


define an anonymous function, you start with fn and add any variable names you’d
like accept in your function enclosed in parentheses and separated by a comma. In
our add_ingredient function in Listing 2.3, we accept two variables and name
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
26

them plate and ingredient. The function body is then indicated by a "stabby
arrow" → and contained between it and an end declaration. Our function body in
Listing 2.3 adds the new ingredient to the plate. Note that Elixir functions
implicitly return the result of the last line of the function body.

Listing 2.4. Creating an anonymous function and binding it to


the add_ingredient variable

iex(1)> add_ingredient = fn(plate, ingredient) -> plate ++ [ingredient] end ❶


#Function<12.52032458/2 in :erl_eval.expr/5>

❶ We are using a List for our ingredient list. We cover Lists in detail later in this chapter.

Let’s now take our knowledge of anonymous functions and expand our psuedocode
above to be a little bit more functional.

Listing 2.5. listing name

for each order received:


plate = new_plate(order) ❶
plate = add_ingredient.(plate, :bread)
plate = add_ingredient.(plate, :mustard)
plate = add_ingredient.(plate, :turkey)
plate = add_ingredient.(plate, :cheese)
plate = add_ingredient.(plate, :lettuce)
plate = add_ingredient.(plate, :tomato)
plate = add_ingredient.(plate, :bread)
return plate to customer
end

❶ Don’t worry, you didn’t miss anything. new_plate/1 is currently not defined in our psuedocode. But
you can imagine what it might do.

Calling anonymous functions differs slightly than calling named functions that are
contained within a module. We must use the variable name we bound our function
to (add_ingredient for us Listing 2.TODO) followed by a dot and open and close
parentheses. Inside the parentheses you would put your values to pass to the
function.
add_ingredient.(plate, ingredient)

Most of the time, your functions will require multiple lines and can be written as
such. Whitespace such as newlines are generally not strictly enforced in Elixir.
iex(1)> add_ingredient = fn(plate, ingredient) ->
...(1)> plate ++ [ingredient]
...(1)> end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
27

We won’t be writing many anonymous functions like this in this book. There are
times where we WILL be writing them, such as when using them when performing
some action over a set of data, but we won’t be binding them to a variable very
often. An example of an anonymous function that isn’t saved for later is in Listing
2.4. Don’t worry too much about the syntax or what it is doing, just try to
recognize the anonymous function being used.

Listing 2.6. Using an one-time anonymous function in Enum.filter/2

iex(1)> Enum.filter([1, 3, 5, 7, 9], fn(x) -> x < 6 end)


[1, 3, 5]

2.1.3 Data Type Details


While you’ve been introduced to some basic data types in Elixir, we haven’t really
dug into them very much. Here’s some extra details on the types introduced above
and some example usage.
INTEGERS AND FLOATS
Numbers in Elixir are pretty straightforward, but there are a few things you’ll need
to know before we dive into other data types.
1. When writing a Float that is between -1 and 1, it must be preceded by the 0
(i.e. 0.125, -0.87).
2. The division operator / always returns a Float value, even when dividing two
Integers. div/2 does Integer division and rem/2 returns the remainder of a division
if those values are required.
iex(1)> 8 / 4
2.0
iex(2)> 8 / 5
1.6
iex(3)> div(8, 5)
1
iex(4)> rem(8, 5)
3

3. You can round a value by using the round/1 function. trunc/1 returns just the
Integer portion of a Float value.
iex(1)> round(1.6)
2
iex(2)> trunc(1.6)
1

BOOLEANS
Booleans simply represent a true or false value.
iex(1)> 1 == 5 ❶
false

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
28

iex(2)> is_integer(5)
true

❶ The double-equals == tests for equality.

STRINGS
As you’ve seen in the above examples, Strings are enclosed in double quotes ("a
string") and importantly not single quotes ('not a string') which are Charlists
(explained a bit later on in this chapter). Since Elixir supports UTF-8/Unicode by
default, strings are stored as a UTF-8 encoded binary where each character is
actually stored as its unicode bytes. Because of that, Elixir considers Strings a
binary type. Listing 2.5 gives a number of examples of working with Strings.

Listing 2.7. Examples of using Strings in Elixir

iex(1)> is_binary("Phoenix in Action")


true

iex(2)> "Phoenix" <> " in " <> "Action" ❶


"Phoenix in Action"

❶ Use the <> operator to concatenate (join) Strings

For longer, multi-line Strings (like documentation), it may be easier to define them
with """ (known as heredoc). Everything inside the opening and closing """ will be
retained, including spacing and line feeds.
iex(3)> haiku = """
...(3)> Build web apps for fun, profit
...(3)> Phoenix in Action
...(3)> Learn the things you need to know
...(3)> """
"Build web apps for fun, profit\nPhoenix in Action\nLearn the things you need to
know" ❶

❶ \n is the ASCII character for a new line

Strings can also be interpolated with #{ }. Interpolation prints the String value of
the code or variable contained withing the curly braces.
iex(4)> subject = "Phoenix"
"Phoenix"

iex(5)> "#{subject} in Action"


"Phoenix in Action"

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
29

Further information can be found in Elixir’s String documentation. 4


CHARLIST
There is one type that we’ve introduced that you need to pay special attention to
because it has a gotcha: the Charlist. In Elixir, a String must be denoted using
double quotes (") while Charlists are denoted using single quotes ('). A Charlist is
actually a special kind of List — a List of ASCII number values that represent the
characters and not the characters themselves. This may sound like a minute
distinction, but as you can see in Listing 2.6, this can lead to some funky and
unexpected results.

Listing 2.8. Discovering Charlist gotchas

iex(1)> 'Geo'
'Geo'

iex(2)> i('Geo') ❶
Term
'Geo'
Data type
List ❷
Description
This is a list of integers that is printed as a sequence of characters
delimited by single quotes because all the integers in it represent valid
ASCII characters. Conventionally, such lists of integers are referred to as
"charlists" (more precisely, a charlist is a list of Unicode codepoints,
and ASCII is a subset of Unicode).
Raw representation
[71, 101, 111] ❸
Reference modules
List
Implemented protocols
IEx.Info, Collectable, Enumerable, Inspect, List.Chars, String.Chars

iex(3)> [71, 101, 111] ❹


'Geo'

iex(4)> {71, 101, 111}


{71, 101, 111}

❶ We use the i/1 function to inspect information about the passed value ('Geo').
❷ Elixir sees this term ('Geo') as a List data type and not a String because we used single quotes.
❸ Elixir informs us that internally, our 'Geo' is represented by the list [71, 101, 111].
❹ So what happens if we use that raw data? What will Elixir echo back to us? Crucially, we give it a List
of integers and it gives us back a Charlist of 'Geo'.

If you look again at callout #4 from Listing 2.6, you can potentially imagine a
4
hexdocs.pm/elixir/String.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
30

confusing scenario. Let’s say that you have a function that returns a List containing
the results of three calculations which return three Integers (perhaps X, Y, Z
coordinates). You run the function and our iex session reports back to us that the
result is 'Geo' — it doesn’t look like a List at all, especially not one filled with
three integers. But it is (71, 101, and 111). In these cases, IEx is trying to be smart
and helpful about how to display the data it received but it turns out to be
confusing, especially to beginners. One thing to remember is that your data is still
there as you’d expect it to be (those three integers representing your X, Y, Z
coordinates) but IEx displays it in this way.
We won’t be using Charlists much at all in this book. In fact, as an Elixir
developer, I’ve still rarely had the need for a Charlist and not a String. They are
mostly a holdover from Erlang. However, this particular gotcha exists and so we
needed to discuss it before moving on. Speaking of moving on…
ATOMS
Atoms in Elixir are like Symbols in other languages. Atoms start with a colon (:),
are constants, and they are their own value. For example, :foo can never mean or
be more than :foo — it can’t be re-bound, it’s value (:foo) cannot change, and
what you see is what you get. When I initially came across Atoms, it seemed like
there should be more to them … but there isn’t. They really are that simple.
Atoms are used regularly in Elixir, especially in situations in which a function
returns a status along with a value. Let’s take, for example,
the Enum.fetch/2 function. It’s documentation states
Finds the element at the given index (zero-based).

Returns {:ok, element} if found, otherwise :error.

We can demonstrate this by using Enum.fetch/2 in an IEx session. First, we look


for a value for the position that does exist in the List (the second item in this List).
Next, we try to fetch the value for a position that does not exist in the List (the 15th
item in the List). Notice that the return values contain Atoms.
iex(2)> Enum.fetch([1, 2, 3, 4], 1) ❶
{:ok, 2}
iex(3)> Enum.fetch([1, 2, 3, 4], 14) ❷
:error

This pattern will be often-repeated in Elixir. You will see it all over the place and
because of that, it will be a good idea to start writing a lot of your functions with
the same pattern.
One caveat to Atoms is that it is the only Elixir data type that is not garbage
collected. Without getting into the nitty-gritty of computer science, that means that
if you create enough Atoms, you can crash your system as it runs out of memory
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
31

trying to allocate too many Atoms. If you are handling user-inputed data, it is a
good idea to avoid using Atoms for those as an overload of them can be used an
attack vector against your server.
LISTS
You can think of a List in Elixir as like an Array from other languages or as simply
a list of items that may or may not be similar types. Depending on the language
you are most familiar with, it even has similar syntax. Practically, it is a list of
items contained in a single type (we will see in a moment that they are more than
that, though). Lists can contain any other Elixir types (even mixed types) and can
even contain references to other Lists.
iex(1)> list = [1, 2]
[1, 2]
iex(2)> [:numbers, "for example", list]
[:numbers, "for example", [1, 2]]

The interesting thing about Lists in Elixir is that they are linked lists. That means
that each item in the list has an internal pointer to the next item in the list (see
Figure 4). You will never interact, see, or really know anything about that internal
pointer — just trust that it is there. Practically, that means that a number of typical
operations are fast and memory-kind. It is efficient to add items to the beginning of
a List, but adding items to the end of the List can get slower as the List grows in
size. The advantages and disadvantages of linked lists are a deep computer science
topic that we won’t dive into, but if you’re interested in some addition reading on
the topic, Wikipedia actually has a nice summary. 5
Figure 2.5. Lists are linked meaning each entry contains a pointer to the next item’s memory
location.

Lists can be concatenated and subtracted using ++ and --.

5
en.wikipedia.org/wiki/Linked_list
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
32

iex(1)> [1, 2] ++ ["three", :four]


[1, 2, "three", :four]
iex(2)> [1, 2, 3] -- [1, 3]
[2]

We will do a number of things with Lists in our time in Elixir and you will often
hear about the "head" and "tail" of a List — so much so that there are built-in
functions and patterns we will use for both. The "head" of a List is, as you’ve
probably guessed by now, the first item in the List. The "tail" is everything in the
List that isn’t the head (in other words, the rest of the List).

Figure 2.6. Each List has a head and a tail. You can use | to separate the head from the tail.

iex(1)> [head | tail] = ["Phoenix", "in", "Action"] ❶


["Phoenix", "in", "Action"]
iex(2)> head
"Phoenix"
iex(3)> tail
["in", "Action"]

❶ The | character is used to denote the break between the head and tail. I affectionately call it the
"guillotine" as it separates the head from the rest of the List.

The hd function returns the head of a List (but, as in all of Elixir, does not modify
the value sent to it).
iex(4)> hd(tail)
"in"

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
33

iex(5)> tail
["in", "Action"]

Internally, since Elixir uses linked lists, we can actually write out how Elixir "sees"
them (as a value acting as the head, followed by another List as the tail). The head
of this is List 1. The tail is itself a List comprising of 2 as its head and an empty
List as its tail.
iex(1)> [1 | [2 | []]]
[1, 2]

We can use this pattern to easily prepend items to a List.


iex(1)> trees = ["Oak", "Pine"]
["Oak", "Pine"]
iex(2)> more_tress = ["Maple" | trees]
["Maple", "Oak", "Pine"]

There are lots of powerful functions and great documentation online. If you want to
dive further in, check out Elixir’s documentation. 6
TUPLES
Tuples are stylistically similar to Lists but instead of being surrounded by square
brackets ([ and ]), Tuples in Elixir are surrounded by curly braces ({ and }). They
can also store a undetermined number of elements of differing types like Lists can.
Underneath the hood, however, Tuples are different. They are ordered and store
their data contiguously in memory. Therefore, accessing any element in the Tuple
is a constant-time operation (unlike Lists).
The Elixir documentation is so good, I’ll let it take over the next paragraph:
Tuples are not meant to be used as a “collection” type (which is also suggested
by the absence of an implementation of the Enumerable protocol for tuples):

they’re mostly meant to be used as a fixed-size container for multiple elements.


For example, tuples are often used to have functions return “enriched” values:
a common pattern is for functions to return {:ok, value} for successful
cases and {:error, reason} for unsuccessful cases.

As discussed in the section regarding functions, we will see the {:ok,


value}/{:error, reason}
pattern all over Elixir and Phoenix. Get used to it and
learn to love it.
You can use the Kernel.elem/2 function to access a zero-based index of a Tuple.

6
hexdocs.pm/elixir/List.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
34

iex(1)> tuple = {:ok, 5, ["Phoenix", "in", "Action"]}


{:ok, 5, ["Phoenix", "in", "Action"]}
iex(2)> elem(tuple, 1)
5

For more information regarding Tuples, check out Elixir’s documentation. 7


MAPS
Maps are key-value stores in which each value can be bound to a necessarily-
unique key. In other languages, similar structures can be called Hashes or
Dictionaries. The keys can be any data type as can the values they are related to.
Ordering within a Map is also not deterministic so you cannot rely on a Map to
return its pairs in the same order in which you wrote them. Maps are defined by
enclosing its contents in %{}. The key of the entry is entered first and its
corresponding value is separated by a ⇒. Listing 2.7 goes through some examples
of using Maps in an IEx session.

Listing 2.9. Playing with Maps in IEx

iex(1)> %{:status => 200, "content" => "Hello world!"}


%{"content" => "Hello world!", :status => 200}

iex(3)> Map.fetch(map, [1, "world"]) ❶


{:ok, :hello}

❶ We can use the Map.fetch/2 function to access a Map’s value for a given key.

A shorthand syntax to use when using Atoms in a Map as either the only keys or
the last-passed keys is the Atom name followed by a ':' and the the value for that
Atom’s key. For example, %{a: 1} is functionally the same as %{:a ⇒ 1} but is
shorter to write and, in my humble opinion, nicer to look at. However, we can’t use
this syntax if we follow it with keys of a different type. Elixir will complain to us
about this syntax and we see that complaint in Listing 2.8. Elixir doesn’t know
what to do with this type of syntax mixing but if the shorthand is used in the last-
passed keys, it is possible.

Listing 2.10. Using the alternate Atom key syntax for Maps

iex(4)> %{a: 1, b: 2, c: 3}
{:b => 2, :a => 1, :c => 3}

iex(5)> %{a: 1, "hello" => :world}


** (SyntaxError) iex:5: syntax error before: a

iex(6)> %{"hello" => :world, a: 1}

7
hexdocs.pm/elixir/Tuple.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
35

%{:a => 1, "hello" => :world}

Apart from the Map.fetch/2 function used in Listing 2.7, there are other, potentially
more often-seen ways to access a key’s value in a Map. We can use
the map_name[key] shorthand to access a Map’s value for the specified key. This
works for Atom keys and String/Binary keys. In fact, it works with any of the key-
types in Elixir.
Another way to access Atom-based keys is by separating the variable name and the
key to be retrieved with a .. However, unlike the [key] style of access, this style of
access only works with Atom-based keys as we can see in the error provided in
Listing 2.9. Elixir specifically looked for the key :hello in our Map.
Listing 2.9 contains examples of both of those methods.

Listing 2.11. Alternative Map value access

iex(1)> map = %{"hello" => :world, a: 1}


iex(2)> map[:a]
1

iex(3)> map["hello"]
:world

iex(4)> map.a
1

iex(5)> map.hello
** (KeyError) key :hello not found in: %{:a => 1, "hello" => :world}

We will be using Maps a lot in our time in Elixir and Phoenix, so take some time to
play with them in your IEx session. Also, read up on the power of Maps and some
of the included functions in the Map documentation. 8
2.1.4 Back to Modules and Named Functions
Of course, most of your code will not be simple anonymous functions. We will be
organizing and reusing large portions of your codebase. When we do that, we will
need to create modules and have functions live inside those modules. For
organizational sanity, functions that have things in common are grouped into
modules. For example, if you had a group of functions that did any number of
mathematical calculations, you may group those together in a Math module.
Now that we’ve taken a look at the module as a whole, let’s break down a few
interesting sections of the module.
All module definitions start with defmodule followed by the name of your module

8
hexdocs.pm/elixir/Map.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
36

and do. Module names are CamelCased and you can namespace modules as well
with dot notation (.). For example, if we had a subset of Math functions that dealt
with mortgages, we could create a Math.Financial.Mortgage module. For now
though, let’s keep our Math module simple.
defmodule Math do
# ...
end

A function inside a module is defined with def followed by the function name and
any arguments it accepts. For our add function, we are accepting two arguments
and assigning them variable names of aand b. Since Elixir implicitly returns the
result of executing the last line of the function, we don’t have to explicitly return
the value of adding a and b.
def add(a, b) do
a + b
end

There also exists a shorthand function definition. When your function does one
thing or is a one-liner, it can be helpful to use this shorthand version of the function
definition. The differences between the multi-line and one-line function definitions
are small, but there is an addition of a , after the argument collection (e.g. (a, b))
and a : after do. Also note the lack of end.
def subtract(a, b), do: a - b

Functions can take any number of arguments and if they take none, the parentheses
can be omitted entirely.
def one, do: 1

Elixir allows you to define multiple functions with the same name. How does it
know which one to actually execute? It does pattern matching on the function
signatures and uses the first one that matches. We go deeper into pattern matching
later in this chapter, but for now, think of it as just looking for the function
signature. A function signature is its name and the amount of arguments it accepts
(or it’s "arity").
For even_numbers, we have one function that expects two arguments and one
function that accepts zero or one arguments. Functions can have default argument
values and can be specified by the \\characters. We can call even_numbers with a
single number and have it find even numbers from 0 to the provided number or call
it with no arguments and have it default to returning even numbers from 0 to 10.
Stylistically, functions with the same name are grouped together.
Functions inside a module can call other functions inside the same module without
using the module prefix. If there is ever a cause for confusion over function names,
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
37

you can always use the full name of the function (Math.even_numbers) instead.
def even_numbers(min, max) do
Enum.filter(min..max, fn(x) -> rem(x, 2) == 0 end) ❶ ❷
end
def even_numbers(max \\ 10) do
even_numbers(0, max)
end

❶ min..max simply creates a Range of Integers from min to max. A Range is what it sounds like, a
collection of all numbers between and including two numbers.
❷ rem/2 returns the remainder of dividing the first argument by the second. rem(x, 2) equals 0 for
even numbers.

Functions that you need to call internally but you don’t want exposed to the outside
world can be defined as private. You do this by using defp instead of def when
defining the function.
defp internal_calculation(x), do: 42 + x

Listing 2.10 shows what our group of functions that deal with doing simple
calculations might looks like now.

Listing 2.12. Example Math module

defmodule Math do
def add(a, b) do
a + b
end

def subtract(a, b), do: a - b

def one, do: 1

def even_numbers(min, max) do


Enum.filter(min..max, fn(x) -> rem(x, 2) == 0 end)
end
def even_numbers(max \\ 10) do
even_numbers(0, max)
end

defp internal_calculation(x), do: 42 + x


end

A few more quick tips about modules before we move on:


ALIAS

If you have a module name that is deeply namespaced and you don’t want to type
its long name every time, you can alias it and from there on use only the last

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
38

portion of the module name.


defmodule MyMortgage do
alias Math.Financial.Mortgage

def amount(args), do: Mortgage.calculate_amount(args)


end

Figure 2.7. alias vs import. alias allows you to shorten the module name
while import allows you to forego it entirely.

IMPORT

You can further reduce typing and import the functions of a module into your
module as well (demonstrated in Listing 2.11). That will allow them to be called
without the module name prepended. If you import a function without any
arguments, all the public functions will be available. However, you can limit which
functions are brought in by providing an only argument and a List of which
functions and their arity you’d like to import. Listing 2.11
imports Math.Financial.Interest.rate/1. Once the functions are imported, we can
call them without using their full module names.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
39

Listing 2.13. Importing functions from external modules

defmodule MyMortgage do
import Math.Financial.Mortgage # contains calculate_amount/1
import Math.Financial.Interest, only: [rate: 1]

def amount(args), do: calculate_amount(args)

def interest_rate(args), do: rate(args)


end

2.2 Other Idiomatic Elixir Language Features


While some of the discussion we’ve had so far is somewhat dry, it sets the stage for
your usage of Elixir in the context of Phoenix. Most of the basics have been
covered above, but there are some other really cool, idiomatic, and useful Elixir
features that we will be utilizing extensively in our time with the language. Let’s
look over them.
2.2.1 The Pipe Operator
One of my favorite things about the Elixir language syntax is the pipe operator and
how just using it can help clarify the flow of information from one function to
another. When used correctly, it will make you wish every other language could
and would implement the same (and some are working on it!). So what is it? Take
a look: |>. Looks benign and unassuming doesn’t it? It’s not super flashy, but it is
very powerful. In short, it allows you to pass one value into a function call as the
first argument of that function call. With the pipe operator, the following two calls
do the same thing.
Module.function(first_argument, second_argument)

first_argument |> Module.function(second_argument)

Why is that helpful? Why not just pass it in directly as the first argument? Let’s
look back at our Deli from earlier in the chapter in Listing 2.TODO.

Listing 2.14. Deli psuedocode

for each order received:


plate = new_plate(order)
plate = add_ingredient.(plate, :bread)
plate = add_ingredient.(plate, :mustard)
plate = add_ingredient.(plate, :turkey)
plate = add_ingredient.(plate, :cheese)
plate = add_ingredient.(plate, :lettuce)
plate = add_ingredient.(plate, :tomato)
plate = add_ingredient.(plate, :bread)
return plate

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
40

end

Look at all that re-binding of plate. Pretty ugly and repetitive, isn’t it? But you
will notice something about how we wrote our add_ingredient/2 function: the first
argument is expecting the current state of the plate. Not only that, our function
returns the new state of the plate after adding the ingredient. We can use the pipe
operator in Listing 2.TODO to clean up this code greatly.

Listing 2.15. Deli psuedocode with the pipe operator

for each order received:


new_plate(order)
|> add_ingredient.(:bread)
|> add_ingredient.(:mustard)
|> add_ingredient.(:turkey)
|> add_ingredient.(:cheese)
|> add_ingredient.(:lettuce)
|> add_ingredient.(:tomato)
|> add_ingredient.(:bread)
end

Our plate variable is now gone! We have bound no variables in our process of
creating our masterpiece of a sandwich. Instead, we are just taking the result of one
function and letting the next function use it, passing the state of our plate down
through the assembly instructions for our sandwich. Finally,
since add_ingredient/2 returns the state of the new plate, that means that at the end
we return the plate implicitly to the customer.
When writing your functions, it is normally worth the extra time to consider
exactly how you want the data in your application to flow. With that in mind, you
can arrange the functions like we have above so that our Elixir code can read just
like the assembly instructions.
Get to know and love the pipe operator because you will see it all over the
place during your time in Elixir and you will be writing it a lot. And believe
me, you will love it.
2.2.2 Pattern Matching
Think back on your personal experiences with sandwiches. How do you recognize
a sandwich? By the way it smells? Perhaps. By the way it sounds? Probably not.
By the way it looks? Most likely, yes. How would you describe a sandwich?
Typically, they are made up of smaller building blocks such as bread and meat like
in our examples from the section on the Pipe Operator. But you don’t typically
recognize a sandwich by piecing together all the smaller parts and then deciding it
is a sandwich. Normally, you can recognize the pattern of those smaller objects
that create a sandwich.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
41

For example, you would typically make a turkey sandwich using some variation of
bread, condiment(s), meat, cheese, lettuce, tomato, and other desired toppings. You
can see each individual piece (and name them), but also see the whole at the same
time. That is because your brain is wired to recognize patterns. Elixir is also wired
to recognize patterns.
Suppose you wanted to verify that an object you’ve been given is a grilled cheese
sandwich? Someone hands it to you and says "here’s a grilled_cheese_sandwich!"
but you’re not sure if you can trust them. You would use what you know about
grilled cheese sandwiches and use pattern recognition. Bread, cheese, then bread
again? If so, then you’ve verified the pattern. The same can be done with Elixir.
iex> grilled_cheese_sandwich = [:bread, :cheese, :bread]
[:bread, :cheese, :bread]
iex> [:bread, :cheese, :bread] = grilled_cheese_sandwich
[:bread, :cheese, :bread]

Figure 2.8. Pattern matching compares the two sides of a call. If everything matches, it is a
successful match. If one side is different than the other, an error will be returned.

The first call actually set up our variable with a List of Atoms. The second call
does the pattern check. The fact that we did not receive an error on our second IEx
call verifies that the pattern we told it to expect on the left side of the = sign is
indeed the pattern on the right. What would have happened if the patterns were
different?
iex> [:bread, :cheese, :salami, :bread] = grilled_cheese_sandwich
** (MatchError) no match of right hand side value: [:bread, :cheese, :bread]

We get a MatchError which tells us that the pattern we told it to expect


with :salami is not what is on the right hand side. This works for any Elixir type.
Beyond simple pattern verification with explicit values, we can give it a pattern to

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
42

expect with variable placeholders and bind the unknown values to those
placeholders. Suppose we knew this strange sandwich-giver gave
us something between two pieces of bread, but we weren’t sure what it was. We
can verify what we know about the pattern and bind the unknown to a variable to
learn what it is in between those slices of bread.
iex> [:bread, mystery_meat, :bread] = unknown_sandwich
[:bread, :olive_loaf, :bread]
iex> mystery_meat
:olive_loaf

We can now use that mystery_meat variable later in our code (perhaps to decide
whether or not to actually eat the strange sandwich).
As previously stated about Atoms and Tuples, a pattern you will see a lot in Elixir
is {:ok, value} or {:error, reason}. This is an idiomatic pattern because it is easy
to match on in your code to decide whether to continue operation or present an
error to the user. Take, for example, the Map.fetch/2 function. It takes a map and a
key and, if it finds that key in the given map, it will return that key’s value as {:ok,
value}. If the given map does not have the provided key, it will return :error. We
can use that knowledge to search our memory to see if the mystery meat is one we
will eat.
iex> edible_meats = %{turkey: true, chicken: true, ham: false, olive_loaf: false}
iex> {:ok, edible} = Map.fetch(edible_meats, :turkey)
{:ok, true}
iex> edible
true

We will eat the turkey! Now let’s use our mystery_meat to see if we will eat that.
iex> {:ok, edible} = Map.fetch(edible_meats, mystery_meat)
{:ok, false}
iex> edible
false

So we’ll pass on the olive loaf sandwich. But what happens when we’re given a
meat we’ve never encountered—one for which we have no listing in our Map? We
expect to get an error, right?
iex> {:ok, edible} = Map.fetch(edible_meats, :head_cheese)
** (MatchError) no match of right hand side value: :error

Our pattern match failed because we expected {:ok, value} but instead got :error.
Awesome! Elixir can tell you when an unexpected pattern is used. Let’s write a
little function in a module using pattern matching that will help us decide whether
we will eat a mystery sandwich.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
43

Figure 2.9. Sandwich.accept?/1 decision diagram.

Here’s how we’ll make our decisions. When we receive a sandwich:


1. Set up our Map of acceptable meats to us.
2. Use pattern matching to pull the mystery meat out of the List (Yes, this means that
this function only works if there is one thing between two slices of bread. You can
expand this if you’d like, but we’ll keep it simple for now.)
3. See if that meat is in our list of known meats
4. If it is and it is edible, we’ll return "Thanks!"
5. If it is in our list of known meats and we don’t like that particular meat, we return
"No thanks."
6. If we get an :error, which means that meat isn’t in our list of known meats, we’ll
return "I don’t even know what that is!"

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
44

Listing 2.16. Should we eat the mystery sandwich?

defmodule Sandwich do
def accept?(sandwich) do
edible_meats = %{turkey: true, ham: false, chicken: true, olive_loaf: false}
[:bread, mystery_meat, :bread] = sandwich

case Map.fetch(edible_meats, mystery_meat) do


{:ok, edible} ->
if edible, do: "Thanks!", else: "No thanks."
:error ->
"I don't even know what that is!"
end
end
end

Let’s use our new function.


iex> Sandwich.accept?( [:bread, :turkey, :bread] )
"Thanks!"
iex> Sandwich.accept?( [:bread, :olive_loaf, :bread] )
"No thanks."
iex> Sandwich.accept?( [:bread, :head_cheese, :bread] )
"I don't even know what that is!"

We will often reach for the case statement to pattern match a variety of expected
results in order to correctly respond to the result of a function.

The Pin Operator


There will also be times where we won’t know what a value will be in a given pattern and we
want to bind it, but then use the value of that variable in a future binding. In the pattern
matching we’ve seen so far, that won’t quite work:

iex(1)> [:bread, mystery_meat, :bread] = [:bread, :turkey, :bread]


iex(2)> mystery_meat
:turkey

iex(3)> [:bread, mystery_meat, :bread] = [:bread, :ham, :bread]


iex(4)> mystery_meat
:ham

We would have expected an error in call 3 because we wanted to ensure we got the same
sandwich twice, no matter what the mystery_meat was. Instead, we re-
bound mystery_meat to :ham. How do we "pin" the value of a variable in pattern matching
like this? Well, with the pin operator ^! Using it, we can pin the value in a pattern match so
that we can match on that variables value instead of re-binding it with the right-side value.

iex(1)> [:bread, mystery_meat, :bread] = [:bread, :turkey, :bread]


iex(2)> mystery_meat

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
45

:turkey

iex(3)> [:bread, ^mystery_meat, :bread] = [:bread, :ham, :bread]


** (MatchError) no match of right hand side value: [:bread, :ham, :bread]
iex(4)> mystery_meat
:turkey

This time, because we pinned our variable ^mystery_meat, we didn’t re-bind it but instead
attempted to match on its value. And since the right hand side of the pattern match didn’t
match the left, we got a MatchError. Finally, we verify that our mystery_meatvariable
wasn’t re-bound to a value of :ham and instead retains its original :turkey value.

Pattern matching Maps can be fun and very code-efficient. Here we look to pattern
match the key of :bass from our band variable which contains our Map of band
member names. If we do find a :basskey, we ask Elixir to bind the value of that
key to the variable of name. Finally, we verify that we indeed now have "Adam" as
the value of name straight from our band Map.
iex(7)> band = %{vocals: "Paul", guitar: "Dave", bass: "Adam", drums: "Larry"}
iex(8)> %{bass: name} = band
iex(9)> name
"Adam"

There are occasions in which you want to make sure a pattern is matched but don’t
really care about storing a value away for later use, nor care which value is
even in a particular position. For example, we’ve used the Map.fetch/2 function
quite often in this chapter and you’ll remember that it returns {:ok, value} on a
successful match. For the times where we don’t want to store that value away, we
can use the character to let Elixir know we expect something in that position, but
don’t really care what.
iex(1)> {:ok, _} = Map.fetch(%{b: 2}, :b)
{:ok, 2}
iex(2)> {_, _} = Map.fetch(%{c: 3}, :c)
{:ok, 3}

You can also prepend variable names with an underscore (_) in order to give the
value an identifier, but also let Elixir know that you don’t expect to use that
variable’s value anywhere in your code.
iex(1)> {:ok, _name} = Map.fetch(%{vocals: "Paul"}, :vocals)

Pattern matching is not only incredibly useful and fun to use, it is also something
that is used quite often in Elixir code. We will also be writing a number of
functions that use pattern matching in Phoenix. Take some time to play with some
pattern matching in Elixir.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
46

2.2.3 Using IEx.Helpers.v/1


Even though I’ve used IEx for quite awhile now as I’m working in Elixir, I often
have times in which I’ve forgotten to capture the output of a long command or
want to go back in history to a different function’s result. Iex provides a nice helper
function named v to help us out. You may have noticed the number
following iex in your iex sessions (ie iex(3)> `). This is when those will move
from being visual noise to being potentially very helpful. When called
without an argument (`v()), v/1 will return the last result again. When passed an
argument (v(3)), v/1 will return the result of the passed iex expression (in the
example’s case, 3. Let’s take a look at some usage in Listing 2.20.

Listing 2.17. Using v/1

iex(1)> 1 + 5
6

iex(2)> six = v()


6

iex(3)> six + 3000


3006

iex(4)> (0.0056283568467 * 1000) |> round()


562

iex(5)> v() + v(3)


3568

While you won’t be using this helper function at all in your own modules, it can be
incredibly useful as you are either learning or experimenting with Elixir in an IEx
session, or even debugging your code trying to figure out exactly how things work.

2.3 Going Deeper


The Elixir we’ve gone over in this chapter in just enough to get you started in the
wonderful, powerful, deep, fun language. As this is ultimately a book about
Phoenix and not Elixir, we’ll have to end our discussion here. However, if you’d
like to dig deeper, there are some other great resources out there for you to
consume.
2.3.1 On the Web
• Elixir’s own Getting Started Guide: elixir-lang.org/getting-
started/introduction.html
• Elixir’s online documentation: hexdocs.pm/elixir/Kernel.html
• Elixir School: elixirschool.com/en/

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
47

2.3.2 Books
• Elixir in Action by Sasa Juric
• The Little Elixir & OTP Guidebook by Benjamin Tan
2.3.3 Community
• #elixir-lang IRC channel on Freenode
• Elixir Slack community: elixir-slackin.herokuapp.com/
• ElixirForum: elixirforum.com/
There are many other resources available for the budding Elixir developer. Check
out the above resources and do some searches on your own to find your favorite.

2.4 Summary
In this chapter you learned
• To utilize Interactive Elixir (IEx) to practice, experiment, and learn Elixir in an
interactive REPL is an easy way to get to know the basics of the language.
• That asking for help from Elixir itself is relatively easy and very informative by
using the h/1 IEx helper function.
• Most of the basic types of Elixir including Integers, Floats, Booleans, Strings,
Atoms, Lists, Tuples, and Maps. You also learned about Charlists and how they
can potentially be confusing when working in and iex session.
• Creating named functions must be done inside a module while anonymous
functions can be bound to a variable for later use.
• Modules keep your code together into sensible groupings of functions.
• Elixir’s Pipe Operator (|>) is incredibly useful and it can make your code read
more like a sentence written regarding how your data will be transformed from
one function through the next or a bulleted list of transformations our data will go
through.
• To utilize pattern matching in your code to quickly verify the return value is in a
pattern you expect and to grab desired data directly from the structure of the return
value. Pattern matching is also used by Elixir to determine which function to
execute when multiple function definitions have the same name. The first one to
match gets executed.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
48

This chapter covers:



A Little Phoenix Overview

What Phoenix is and how it relates to Elixir


3
• The flow of a web request through Phoenix’s structure
• An overview of the different modules we will be creating in the book
• The nature of data transformation as it flows from one place to the next
• A bird’s-eye view of the basic structure of a blogging application built on top of Phoenix

In the last chapter, you learned some of the basics of the Elixir programming
language. If it was your first introduction to the language, I hope that you spent
some time in an IEx session to play with different concepts and to see how things
work. If you haven’t, consider taking a few minutes to re-orient yourself with the
syntax of Elixir and how you can interact with it — we’ll be looking at and writing
a lot of Elixir from this point on.
In this chapter, we’ll be looking at an example Phoenix application — one that isn’t
too complex and, to be honest, doesn’t really do all that much. But as we will be
just taking a bird’s-eye view of the application, we don’t want complexity to
overshadow the basics of how a Phoenix application is pieced together. The
application we will be looking at is a simple blog engine — one that doesn’t look
pretty but allows the owner to create and edit blog posts and a visitor to read those
blog posts and to create comments on those posts.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
49

Figure 3.1. Our quick-tour application will be a very simple blogging application

In later chapters, we will be building a much more complex web application from
the ground up and dive deeper into the topics being introduced here. Think of it
like this: soon we will be making a custom-built mansion and doing so with our
hands and our tools and starting from a dirt foundation. But this chapter is more
like a tour of a simple house that is already built. Such a tour would introduce you
to the basic concepts of a house if you weren’t really familiar, but you wouldn’t be
able to build your own after the tour. The same goes for this chapter—you won’t be
able to jump in and build your own Phoenix application after reading it, but you’ll
have a better understanding of what we will be building in the future chapters.
In short, if you don’t understand the code itself in this chapter, that is fine. What I
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
50

hope you get out of this chapter is the basic understanding of the different pieces of
a Phoenix application and how they all fit together to take a visitor’s web request
from initial server request to rendered page.
The name of our application will be "Blog". Really creative, huh? It’s important
that you know the name of our application because almost every module defined in
our application will have Blog prepending it which makes it very easy to
namespace. Namespacing not only helps you keep track of your code, but it
provides an easy way to combine applications in the future if you ever need to
merge two applications into one or call one application from another. It also allows
for nice mental and physical code organization.

3.1 Follow the Data


For our dive into Phoenix, we’ll be following the flow of a web request. As you’ll
see in the coming sections, all we are really doing is taking information (data) from
the user’s request and piping that data from one function to another until we have
what we need to form and deliver a response. Since that is the case, following the
flow of data makes for a good starting point for discovering Phoenix’s various
parts.
3.1.1 The Basics of a Web Request
Before we get into the specifics of how Phoenix handles a web request, let’s take a
quick, shallow dive into the details of a web request. For our specific instance,
we’ll discuss an example web request from a web browser such as Chrome,
Firefox, or Safari.
When a user types in the URL of a web site (such as www.phoenixinaction.com),
the request first goes to a DNS server to translate the human-readable name of the
website to a computer-readable IP address which is the ultimate location of the
website. It is like looking in an old telephone book if you needed to translate the
name Geoffrey Lessel into my phone number. We need to do the same with
"www.phoenixinaction.com".
Once we have that IP address (which looks like xxx.xxx.xxx.xxx where "x" is an
integer between 0 and 9), the browser then formats your request into a HTTP
Request Message with details about how it would like to receive data back and
what kind of data it would accept. That Request Message ends up on a server
somewhere in the world. That server interprets the message it receives and either
responds with its own message stating it can’t or won’t respond to that request,
specific file data (such as a JPG or PDF file), or with the result of running a
program on the server. In the case of Phoenix, the server will run a program (our
Phoenix code), forwarding the information about the original request. Phoenix will
then execute its code and will respond to the request appropriately. Phoenix runs
on an Erlang web server known as Cowboy. In our interactions with Phoenix, that

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
51

fact will not really ever come into play, so don’t worry about remembering it or
noting it as important, but it is nice to know.
Figure 3.2. The steps a request takes from the user, through our Phoenix application, back to
the user

Figure TODO shows how our Phoenix application handles a web request to our
blog. Right now, all you see is an empty box that shows where Phoenix comes into
play in the process. In each section of this chapter, we will uncover an additional
step in the Phoenix process that handles the request from the previous step. We’ll
slowly reveal what is inside that Phoenix-shaped box between the point when a
user’s request hits our server and we send the user back the html required to render
a web page in their browser.
The code we will be reviewing is from an already-built application. A surprising

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
52

amount of it is unchanged from the code that Phoenix automatically supplies when
you start a new application, but some of it was added by me to add the blog-like
features we need. All of the code for this simple blog application can be found
at www.phoenixinaction.com/code/blog.
3.1.2 Endpoint
After the Cowboy server handles what it needs to do, our journey with Phoenix
begins and the first piece of Phoenix code that handles this request the Endpoint.
Figure 3.3. The Endpoint is where our data’s Phoenix journey begins

You may be interested to know that even though the Endpoint module in Listing
3.1 runs our Blog web application, nothing of substance in this file has been
written or even edited from what was created for me when I ran mix phx.new (the

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
53

terminal command to use to start a new Phoenix application; we’ll run that
ourselves in an upcoming chapter). The only thing changed from the original is
removing comments and some reformatting due to spacing issues.

Listing 3.1 Blog.Endpoint (lib/blog_web/endpoint.ex) (comments removed)

defmodule BlogWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :blog ❶

socket "/socket", BlogWeb.UserSocket

plug Plug.Static, ❷
at: "/", from: :blog, gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)

if code_reloading? do
socket "/phoenix/live_reload/socket",
Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end

plug Plug.RequestId
plug Plug.Logger

plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Poison

plug Plug.MethodOverride
plug Plug.Head

plug Plug.Session,
store: :cookie,
key: "_blog_key",
signing_salt: "IU3pUWqa"

plug BlogWeb.Router

def init(_key, config) do


if config[:load_from_system_env] do
port = System.get_env("PORT") ||
raise "expected the PORT environment variable to be set"
{:ok, Keyword.put(config, :http, [:inet6, port: port])}
else
{:ok, config}
end
end
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
54

❶ Most of the major components in Phoenix will use another module, bringing its functions into our
module.
❷ The majority of the Endpoint is made up of plugs.

Almost everything you see in listing 3.1 begins with plug. plug is a macro that sets
up a Plug. 9 While we didn’t cover it in the Intro to Elixir chapter, a macro is
essentially a way to write code that writes code. In the Endpoint example,
each plug * line adds a specified Plug to the pipeline that the data from a request
flows through. The flow goes from the top of the file to the bottom of the file and
without any knowledge of what each of these plugs do, you can take a reasonable
guess just from their module names. In our time in Phoenix, we will eventually
write our own Plug module so don’t worry too much about getting a deep grasp
of Plug and its abilities for now.
plug Plug.Static,
at: "/", from: :blog, gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt)

The first plug we encounter is Plug.Static. It’s job is to serve up static files in our
we application. It specifies that we’d like to serve them at /, don’t compress them,
and serve only files in the css, fonts, images, and js directories as well as the
specific files favicon.ico and robots.txt.
if code_reloading? do
socket "/phoenix/live_reload/socket",
Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end

Even though there is no pipeline operator (|>) explicitly shown in


the Blog.Endpoint module, one of the cool things about Plug is it basically pipes
one result into the next, just like the pipeline operator does. So after we have the
static file serving set up, we check to see if code reloading is enabled (which it is
by default in development). If it is, we set up some code live reloading plugs. Live
code reloading simply listens for changes in your code, then automatically reloads
the current page you are on in your browser to show you the updated results. It is
not uncommon for the system to notice the change, send a reload request to my
browser, reload all the data and render it in the browser before I can even bring the
browser window back into the foreground of my monitor. It is blazing fast.
Next, Plug.RequestId simply generates "a unique request id for each request." 10
The data transformation continues into Plug.Logger which sets up logging for your
application. The Logger automatically logs information for each request made to
9
Check out the documentation at hexdocs.pm/plug/readme.html
10
hexdocs.pm/plug/Plug.RequestId.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
55

the server, and you can explicitly log your own information in there as well. From
there, we move into Plug.Parsers which sets up different file handlers. In this case,
you can see that we tell Phoenix we’d like to decode our JSON data with the
Poison package (which is included by default with Phoenix).
The next two plugs are mostly for Phoenix’s benefit under the hood and ones we
don’t need to concern ourselves with too much. The request data is sent
into Plug.MethodOverride which is a plug that overrides some browser requests so
that Phoenix can better handle them. 11 That is then fed into the Plug.Head plug
which is simply "A Plug to convert HEAD requests to GET requests." 12
The final two steps are setting up our session with Plug.Session which will handle
our session data like cookies that we can use to track a User from one request to the
next — important for serving up dynamic web pages that is customized for each
user. Finally, our data is then transferred to the BlogWeb.Router plug, which
ultimately routes the request to the correct handler within our application (and
which we will look at next).
One thing you’ll notice about each of these plugs is the small, focused amount of
work that each is doing. There is a whole Plug that generates a unique ID? That is
pretty focused — and is also a good pattern to follow. When we write our own
plug, we will attempt to do the same: keep the scope small and focused.
3.1.3 Router
The last plug the Endpoint sends the request data through before it is done with its
job is BlogWeb.Router. Now that the Endpoint has done its job, the Router is next in
line to handle the request. This reveals the next step inside our Phoenix box.

11
If you’d like to dive into the docs though, you can so here: hexdocs.pm/plug/Plug.MethodOverride.html
12
hexdocs.pm/plug/Plug.Head.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
56

Figure 3.4. After the Endpoint finishes setting up the request, it passes it to the Router

The Router’s job is to examine the user’s request along with any additional data the
Endpoint added along the way and decide which part of our application should
respond next. It does that by examining the path the user requested (in this
particular case, "/posts/4"), piping that request through appropriate "pipelines",
then sending it on to the appropriate handler.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
57

Figure 3.5. The router decides which controller to send the request to.

Listing 3.2 is a full look at the code in the Router. We’ll take a closer look at each
section following the Listing.

Listing 3.2 BlogWeb.Router (lib/blog_web/router.ex)

defmodule BlogWeb.Router do
use BlogWeb, :router

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
58

pipeline :browser do ❶
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end

pipeline :api do
plug :accepts, ["json"]
end

scope "/", BlogWeb do ❷


pipe_through :browser # Use the default browser stack

get "/", PageController, :index


resources "/posts", PostController do
resources "/comments", CommentController, only: [:create]
end
end

scope "/api", BlogWeb.API do


pipe_through :api

resources "/posts", PostController, only: [:index, :show]


end
end

❶ Each pipeline sets up related plugs that define a specific set of functions relating to different kinds of
requests
❷ Scopes group related request paths and allows namespacing

Within our Router file (Listing 3.2), you can see that we again have a lot
of plug statements. However, these are different than the last in one major aspect:
these are being sent an Atom of a function name as their argument rather than a
module name like in Endpoint. We will get more in-depth about the differences
when we create our own plugs later in the book, but we can again surmise from the
names of the functions what each does.
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end

pipeline :api do
plug :accepts, ["json"]
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
59

The plugs themselves are grouped together into what’s known as a "pipeline". A
pipeline is just a group of plugs that are used for a particular purpose. In
this Router, we have two different pipelines set up: one for a typical browser
request and one for a typical api request. In the browser pipeline, we see that we
are accepting "html" requests, getting the session and the flash (which stores
temporary messages for the user such as success/info/warning messages), we set up
forgery protection for our forms, and finally put secure browser headers into the
data flowing through. However, in the api pipeline, most of that is gone. We only
accept "json" requests. And this makes sense — why get the flash and set up form
forgery protection when a typical API request doesn’t utilize either of those
features? Another important note is that both of these pipelines are set up by
default by creating a new Phoenix application—these pipelines haven’t changed at
all from the default.
This is a good example of the explicitness of Elixir and Phoenix. We can see in
these pipelines exactly what is included or excluded from each type of request.
Why waste the processing power and potential database calls in situations in which
the results of those things are never used?
scope "/", BlogWeb do
pipe_through :browser # Use the default browser stack

get "/", PageController, :index


resources "/posts", PostController do
resources "/comments", CommentController, only: [:create]
end
end

We have the pipelines set up, but we don’t use them until we get into
the scope blocks. The first scope, sscope "/", listens for requests that are at the
root level of our web page ("`/`"). Everything in its do`/`end block can be thought
of children of that root path. So the top-level request
of www.phoenixinaction.com/ would enter into this block. We can see that we first
tell Phoenix that we want to pipe these requests through the :browser pipeline we
set up previously. From there, if it is a GET request to /, then send it to
the BlogWeb.PageController 13 and the index function within that module.
Next we move to the resources call. That single call creates handlers for a full
complement of RESTful actions (index, new, create, show, edit, update, and delete)
at the /posts location. In other words, if a user visits our.blog/posts, it will forward
the request to the BlogWeb.PostController’s `index function. All of those seven
functions are forwarded to the BlogWeb.PostController. Since this resources call
has a do/end block, we can add more routes within it; so we add another resource

13
You’ll notice that the specific get line only contains a reference to PageController. Since this is nested under
the scope "/", BlogWeb call, Phoenix knows to also namespace the calls within it to be under BlogWeb and as such,
will prepend that before any module name.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
60

for /comments handled by the BlogWeb.CommentController. For this resource, we


limit the RESTful actions to only create. 14 We could have also written
resources "/posts", PostController do
post "/comments", CommentController, :create
end

to achieve the same thing. If a user POSTed a form or other data


to our.blog/posts/1/comments where 1 is the id of the blog post they were
commenting on, the BlogWeb.CommentControllermodule would handle that request
with the BlogWeb.CommentController.create/2 function. Besides GET and POST
requests, Phoenix also has function definitions available to set up individual
PUT/PATCH and DELETE requests (among others 15) with, you guessed it, put,
patch, and delete functions.

scope "/api", BlogWeb.API do


pipe_through :api

resources "/posts", PostController, only: [:index, :show]


end

Finally, you can see we’ve also set up a scope for /api which is handled under
the BlogWeb.API namespace. Instead of piping the requests to /api through
the browser pipeline like we did for our / scope, we pipe this one through
the api pipeline we set up in the top of the file. Within our API, we have one
resource, posts, and it is handled by the BlogWeb.API.PostController. We’ve
limited access to only the index and show functions.
Notice how in both scopes we have a PostController. This could have caused
name collisions in other frameworks but remember that the scopes prepend our
controller modules with their own names. In our case, we have
a BlogWeb.PostController and a BlogWeb.API.PostController—two different
controller modules for handling different types of requests for blog posts in our
application.
As with the other sections of this chapter, don’t sweat the details. We’ll dive into
routes and resource in a later chapter and will get much further into the weeds.
If at any time you’d like to see what routes your Router is creating, you can run mix
phx.routes in the terminal from the root directory of your application. Listing 3.3
shows the output of our currently set-up routes.

Listing 3.3 mix phx.routes output

page_path GET / BlogWeb.PageController :index

14
It’s usually a good idea to limit the endpoints of your web application to only the ones you are currently using. Leaving
other ones open could lead to security concerns.
15
hexdocs.pm/phoenix/1.3.0/Phoenix.Router.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
61

post_path GET /posts BlogWeb.PostController :index


post_path GET /posts/:id/edit BlogWeb.PostController :edit
post_path GET /posts/new BlogWeb.PostController :new
post_path GET /posts/:id BlogWeb.PostController :show
post_path POST /posts BlogWeb.PostController :create
post_path PATCH /posts/:id BlogWeb.PostController :update
PUT /posts/:id BlogWeb.PostController :update
post_path DELETE /posts/:id BlogWeb.PostController :delete
post_comment_path POST /posts/:post_id/comments BlogWeb.CommentController
:create
post_path GET /api/posts BlogWeb.API.PostController
:index
post_path GET /api/posts/:id BlogWeb.API.PostController
:show

We can see the route name (post_path, which we’ll cover the use of later), the
method the browser uses to access the route (GET), the path of the route in the
user’s request (/posts), and finally names of the module and function that handles
the request (BlogWeb.PostController; :index).
For our purposes from here on, let’s follow a GET request to /posts/:id. In a
RESTful application, that will typically be a request to see the page for a particular
blog post with the specified ID. We can see from listing 3.3 that that type of
request is forwarded on to the BlogWeb.PostController.show/2 function. Let’s head
into the controller next.
3.1.4 Controller
After the Router handles the initial part of the request, it is passed on to the
controller. This unveils the next step in our Phoenix black box.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
62

Figure 3.6. The Router passes the request into a Controller

And guess what a Phoenix controller is? If you guessed another Plug, you win the
grand prize! The entire purpose of a controller is to gather and set up all the data
that the next steps will require in order to return a response to the requesting user
and decide what kind of response to send. That may or may not include getting data
from a database, an external API endpoint, or some sort of static file. A controller’s
functions are also called "actions". Since we are following a request to /posts/:id,
we’ll look specifically at the BlogWeb.PostController.show/2 function (the "show"
action), which handles the request.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
63

Figure 3.7. The controller makes sure everything is available for rendering the response.

As figure 7 shows, we want our function to gather some specific information to


pass on to the next step in the process. First, we want to get the specific post that
was requested from the database along with any associated comments. Next, we
also want to set up the basic structure of a new comment to seed the comment form
with so we can track any changes the user makes in the form when submitting a
comment. Then we want to render the requested page and make sure to send the
post and new comment along with it.
Listing 3.4 is a truncated look at the controller code:

Listing 3.4 BlogWeb.PostController (lib/blog_web/controllers/post_controller.ex)

defmodule BlogWeb.PostController do
use BlogWeb, :controller

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
64

alias Blog.App ❶

def index(conn, _params) do


# ...
end

def new(conn, _params) do


# ...
end

def create(conn, %{"post" => post_params}) do


# ...
end

def show(conn, %{"id" => id}) do


post = App.get_post_with_comments!(id)
new_comment = App.change_comment(%App.Comment{})
render(conn, "show.html", post: post, new_comment: new_comment)
end

def edit(conn, %{"id" => id}) do


# ...
end

def update(conn, %{"id" => id, "post" => post_params}) do


# ...
end

def delete(conn, %{"id" => id}) do


# ...
end
end

❶ We alias Blog.App so for the rest of the file, any call to App will actually go to Blog.App. It just
saves some typing.

I’ve commented out the details of all the functions except for show/2 so we can
focus on that one function and drill into it. But notice that we have all the different
RESTful actions accounted for: index, new, create, show, edit, update, and delete.
SHOW/2 FUNCTION DEFINITION DETAILS
The first detail we’ll look at in show/2 is the function definition: def show(conn,
%{"id" ⇒ id}) do. We can see that show is going to be passed two
parameters, conn and a Map. Every function in the controller expects the same by
default: a conn and a Map. The Map is actually a Map of the request parameters
from the user. While there could be a large number of parameters that get passed
into the request by the site visitor, the only one we care about in show is
the id param so we use pattern matching to pull out the id from the parameter Map.
If you’ll remember from our list of routes, /posts/:id is the path that gets us to this

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
65

function. The ":id" portion of that route specifies that whatever we put into that
position will be passed as the id in the params Map.
A few more examples of pattern matching the parameter Map in the other
functions:
• For index/2 and new/2, we don’t really care what params are passed in with the
request as it has no bearing on our response. So we ignore the params Map. We
signify the fact that we are ignoring that data by prepending the variable name
with an underscore (_params).
• For create/2, we want to capture all the data that is sent to us in a web form when
an author creates a Post for our blog. We expect all that data to come in via a
param named post and so we capture that data into a post_params variable for
later use (which we don’t see here as I’ve commented it out).
• edit/2 and delete/2 are like show/2 in that the only request parameters we care
about are the id of the Post to work with.
• Finally, update/2 requires both the id of the Post as well as the form data in the
"post" portion of the param Map. The id is required to know which Post to update
with the rest of the data passed in.
SHOW/2 FUNCTION BODY DETAILS
The first line inside our function is
post = App.get_post_with_comments!(id)

The App.get_post_with_comments!/1 function expects the id of a Post to retrieve,


so we pass it the id of the Post as we captured it in the function definition. If the
user requested "/posts/392", then 392 would be passed to the function. If the user
requested "/posts/my-best-day-ever", then "my-best-day-ever" would be passed.
Since we aliased App near the top of the file, the actual full module name
is Blog.App and that is where we’ll find the get_post_with_comments!/1 function
defined. Listing 3.5 contains a truncated look at that module:

Listing 3.5 Blog.App (lib/blog/app/app.ex)

defmodule Blog.App do
import Ecto.Query, warn: false
alias Blog.Repo

alias Blog.App.{Post, Comment}

# ...

def get_post_with_comments!(id) do ❶
get_post!(id)
|> Repo.preload(:comments)
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
66

def get_post!(id), do: Repo.get!(Post, id) ❷

# ...
end

❶ We can define functions that provide us with exactly what we need in the controller in order to set up
the view
❷ Short, one-line functions can be well suited to this function definition shorthand

In the first few lines of the file (listing 3.5), we set up the environment for the rest
of the file by importing and aliasing as needed. Don’t worry about the details of
these lines as we’ll go further in depth in later chapters. For now, know that Ecto is
the package Phoenix uses by default to be our database adapter. It provides
functions that make working with a database easier. The Repo is our "Repository"
that uses Ecto to make those database calls. Again, we’ll get deeper later.
In short, get_post_with_comments!/1 fetches the Post from the database. It does
that by looking it up from the id we passed it. It then then preloads all the
comments associated with it. If we want to display relevant comments, we need to
let the database know ahead of time. Not only is it more explicit, but it reduces
unneeded database calls further down the stack.
def show(conn, %{"id" => id}) do
post = App.get_post_with_comments!(id)
new_comment = App.change_comment(%App.Comment{})
render(conn, "show.html", post: post, new_comment: new_comment)
end

Let’s move back up to the controller. We take the Post fetched from the database
along with all its associated comments and store that into the post variable. On the
next line, we set up a new App.Comment. This may be a bit confusing because we are
using the function named App.change_comment/1 to do so, but since we are passing
it a freshly-initialized struct, it’s basically setting up what is known as a
"changeset" for the new comment. We bind that fresh comment into the
variable new_comment. A changeset allows us and the database to easily track
changes and any validations needed on the comment. We’ll go much deeper into
changesets later in the book and use them extensively.
Once we have those two variables, we head to the last line: render(conn,
"show.html", post: post, new_comment: new_comment). This calls
the render/3 function. The first parameter we pass it is conn, which you’ll notice
every function definition has and uses. What is conn? It’s the connection that we
have been passing from Plug to Plug up to now. It contains all the information
about the request and connection that we’ve captured and set up to this point —
 through the Endpoint and the Router and now to here. It’s officially
a Plug.Conn struct and the render/3 function requires it.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
67

The second parameter we pass render/3 ("show.html") is the template we want


rendered. In this case, we want to render the "show.html" template (we cover
templates in the section after the next one).
Finally, we pass render/3 a Keyword List or Map of the variables we’d like our
"show.html" template to have access to. In our case, we want to pass in
the post and new_comment data that we captured from the first two lines of our
function. In our template, those will be accessible by the name of the key
prepended with a @ (e.g. @post for our post data).
Now that the render/3 function is called, our time within the controller is finished.
So what did the controller ultimately do? It took the request, captured any request
parameters that it needed, set up variables, and finally forwarded the request to the
appropriate View with those variables included.
3.1.5 Views
The next reveal in the Phoenix black box is the View. The View is responsible for
rendering templates (covered next) and for setting up helper functions that you can
use in those templates. The functions defined here are similar to decorators or
presenters that you may be familiar with from other frameworks.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
68

Figure 3.8. The controller calls functions defined in the View

By default, the View module with the name corresponding to the controller module
name is the one that is called. In our application, BlogWeb.PostController will
render the "show.html" template specified in BlogWeb.PostView. Let’s peek into
our App.Web.PostView file in Listing 3.6.

Listing 3.6 Blog.Web.PostView (lib/blog/web/views/post_view.ex)

defmodule Blog.Web.PostView do
use Blog.Web, :view ❶

def date(date_to_display), do: Date.to_string(date_to_display)


end

❶ Most of the functions the template needs is brought in automatically

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
69

Not a lot in there, is there? The majority of the functionality is handled on line 2:
use Blog.Web, :view. This brings a number of functions into our View
including render/3 which ultimately handles the request. You’ll notice that we
don’t define our own render function — it is defined inside that use call. This is
one of the strengths of Elixir — metaprogramming is still possible even though it is
a compiled language. The details of what actually happens there is beyond the
scope of this particular chapter, but know that everything we need to render our
templates is set up in that call.
We also have a lone function that we defined named date/1. Where is this used? In
the templates. We’ll see its usage in the next section. All it is doing is converting a
passed in Elixir Date to a String representation of it. Any function you define in
this view will be available to the templates rendered by it.
Since our controller passed in "show.html" as the template name in
the render/3 call, "show.html" is what the View will attempt to render. Let’s look
at our template.
3.1.6 Templates
We have come to the final step inside our Phoenix black box: the Template.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
70

Figure 3.9. The final step: the Template

The template is responsible for taking the data that we’ve been building up
throughout the different stops in Phoenix and using that to render something back
to the user that requested it. It doesn’t have to be HTML — it could just as easily
be JSON, XML, CSV, etc. In our case, we just want to render back good, old-
fashioned HMTL to be rendered by the user’s browser.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
71

Figure 3.10. The template is what is rendered as a response to the user.

Something very neat about the way Phoenix handles template files is that when
Phoenix compiles, it turns every template file into its own render/2 function inside
its view module. The return value of the function is the resulting HTML from the
template! This means that, yes, rendering is actually just another function and just
another way to transform data. No HTML is stored on disk or in memory and it is
fast.
As we look at the code for our template in listing 3.7, take note of a few things:
1. It is a mix of HTML and Elixir code. You’ll notice the file extension is .eex—it is
an Embedded Elixir file.
2. It is not ALL of the HTML that is ultimately rendered. Where’s
the <html> opener?
3. This won’t render the prettiest web page in the world, but it’s a start. :-)

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
72

Listing 3.7 show.html.eex (lib/blog_web/templates/post/show.html.eex)

<h1><%= @post.title %></h1> ❶

<div>
<p><%= date(@post.inserted_at) %></p> ❷
<%= text_to_html(@post.body) %> ❸
</div>

<hr />

<h4>Comments</h4>
<div>
<%= for comment <- @post.comments do %>
<div>
<em><%= comment.name %> says:</em>
<%= text_to_html(comment.body) %>
</div>
<% end %>
</div>

<hr />

<h5>Post a comment</h5>
<%= form_for @new_comment, post_comment_path(@conn, :create, @post), fn f -> %> ❹
<div>
<label>
Name:<br />
<%= text_input f, :name %> ❺
</label>
</div>
<div>
<label>
Comment:<br />
<%= textarea f, :body %>
</label>
</div>
<%= submit "Submit Comment" %>
<% end %>

<hr />

<div>
<span><%= link "Back", to: post_path(@conn, :index) %></span> ❻
</div>

❶ We render the result of Elixir code by enclosing it in a <%= %> block. Everything else will just be HTML.
Since we passed our Post data into the render/3 call under the post key, it is available to us in this
template as @post. So here we render the Post title attribute.
❷ Here we use the date/1 function we defined in our PostView module.
❸ text_to_html/1 is a helper method provided by the Phoenix.HTML.Format module.
❹ Phoenix.HTML.Form provides the form_for/3 function that allows us to easily set up a form…

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
73

❺ …and provides helper methods to add all the form elements we need.
❻ link/2 renders a link to a specific path. Here, we use the post_path named path we saw in our
routes list from earlier in the chapter.

As with most of the other things in this chapter, don’t worry about understanding
all that is going on in here. We will dive into the details in later chapters. This is
just provided as an overview of what is in these files.

Figure 3.11. The portion inside the box is what was rendered from our template

The output of this EEx template is the boxed portion of our original HTML image
from the beginning of the chapter. So what about the rest of the HTML you’d

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
74

expect like the <html>, <head>, and <body> tags? Those are all provided in a file
known as a Layout. An app can have multiple layouts though typically only use a
handful at most. The layout defines the parts of the page/HTML that are the same
from one page to another like css/javascript includes, analytics embeds, or page
navigation. By default, "app.html" is the layout that is called by Phoenix. We won’t
look in there at this time.

3.2 Putting It All Together


What you’ve just walked through is the typical a web request takes from the initial
handling of the request by the Endpoint, through the Router, into a Controller
which then uses a View to render a Template. All along the way, data is
transformed into exactly what is needed as determined by the initial request. That
is done through Plugs in the initial stages, and then more explicitly in the controller
where you set up the data the View and Template will ultimately need.
One thing I’d challenge you to do is look through more of the source code of the
blog app found at github.com/PhoenixInAction/phoenix-in-
action/tree/master/ch03/blog. Once you have it, try these:
1. Trace a POST request to /posts where we create a new Post for our blog. Can you
figure out what is going on there based on the code?
2. Trace a GET request to /api/posts/:id. How is that handled differently than a
request to /posts/:id?
3. Open up the lib/blog/web/web.ex file. You can see in here all the different
modules that are made available to each of our controllers, views, the router, and
channels (which is a more advanced topic).
Here’s a hint: take the requests through each step as we’ve outlined them in this
chapter. You can skip the Endpoint though, as each of the above requests will be
passed through the Endpoint in the same way. That means the Router should be
your first stop.
In the next chapter, we’ll start building out our own web application from the
ground up.

3.3 Summary
In this chapter you learned
• A web request can be thought of as our Phoenix application receiving a chunk of
data as a request and then modifying and building portions of it as it passes
through our application and is formed into a response to the user.
• The Endpoint sets up the initial portions of the environment in which our data
transformation will live by using Plugs.
• The Router takes the request from the Endpoint and acts as a director of sorts,
taking the request and deciding where to send it next. As it does that, it does some

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
75

of its own data transformation in the form of Plugs, typically in a defined pipeline
that can be shared by multiple scopes.
• The appropriate Controller is called by the Router and handles taking the request
and getting all the data ready that will be needed to present back to the requesting
visitor. Things like fetching information from a database or setting up new structs
to be used in a form happen here.
• The Controller then calls the render/3 function of a View. The View can define
helper methods to use in a Template and also does the work of actually rendering
the appropriate Template.
• Finally, the Template renders the HTML response (for a HTML request) to the
user based on their request. In our example, this included the details of the blog
post along with a list of comments and a form to allow the user to submit their
own comment.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
76

This chapter covers:



Phoenix is Not Your Application—
Just a Boundary

Beginning a new Phoenix application


4
• How Phoenix will interact with the business logic of our application
• Creating our first Elixir module
• The role of a Repo and its usage

Part I covered the basics of Elixir and Phoenix and got you up to speed regarding
basic syntax and the flow of a web request as it traveled from the requesting user,
through the Phoenix framework, and back to the user as a rendered web page. In
Part II, we will be diving into creating a full-featured web application from the
ground up. Our application will be a simple live auction site sort of like eBay. Our
feature list won’t be near as long as eBay’s, but there will be plenty of
opportunities for you to add your own features as we go along.

4.1 I thought this book was about Phoenix


One of the things that is true about Phoenix, potentially more than most web
frameworks, is that it tries to stay out of the way of your real application. What
does that mean in practice? Phoenix should be thought of not as your web
application itself, but just a border of your application that allows your application
to easily "speak web". Your application should be able to be separated from the
Phoenix framework and still be usable to some extent. Decoupling your business
logic code from the Phoenix framework code is something that, while seeming
strange at first, will allow you greater flexibility as your application grows and
more use cases arise.
Figure 1 helps illustrate this fact. There could be many entry points to the business

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
77

logic of your application. In our case, Phoenix is the main one. Starting from the
beginning with the knowledge that your app might be used in multiple ways in the
future is always a good way to go.
Figure 4.1. Phoenix is just a border of your application

That’s really what is meant when it is said that "Phoenix is not your application." It
should be a part of making your application web accessible, but don’t mistake that

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
78

and the business logic of your application. Your underlying application could be
used through the command line or perhaps through embedded hardware. For
example, what if our live-auction application could be integrated with RFID-
enabled bidding devices that enabled real-time, in-person bidding on items with
just a tap? We could make this easier to implement in the future by not locking our
logic inside Phoenix.
Because of this, we will be building our application from the inside out. We will
start with creating the basic building blocks of the business logic in Elixir, and then
focus on the web portion of it with Phoenix. Along the way, we’ll be careful to
keep the database concerns separate from our logic and while we won’t be using a
real database yet, we’ll be using something that will act like a database while we
get up to speed. Figure 2 shows how the different parts of our application will work
by the end of this chapter.
Figure 4.2. The first building blocks of our Auction application. We want to keep the database
and public API separated.

While we won’t have a usable web interface for a while, our initial application will

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
79

be usable through IEx. It will be built step by step from defining what an auction
item looks like in our database, to defining a set of items to store in an in-memory,
fake "database", to finally being able to interact with those Items and our
"database". By the end of this chapter, you will be able to:
1. List all the Items in the database
2. Get a specific Item based on its ID in the database
3. Get a specific Item based on other defining attributes
There will be four initial pieces to our application:
1. An Auction.Item module that defines the data structure for our auction items.
2. An in-memory, fake "database" that we will use to store a list of items for us to
interact with.
3. A module (Auction.FakeRepo) that directly interacts with our database.
4. A module (Auction) that will provide a public API in order to get the data we
need.
4.1.1 Defining an Item
In this chapter we will create the first building block of our auction site: an auction
Item. The purpose of our Item will be to represent the data about the different
things up for bid on our site. Eventually, it will also house some other functions
that will help us deal with various aspects of maintaining our item.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
80

Figure 4.3. Our first step is defining what an Item is

For now, we will create our first struct that will contain the structure of an Item in
our auction’s marketplace. Make a directory somewhere in your development
environment. We’ll use this directory as our playground of sorts while we start our
development.
Figure 4.4. Create a folder somewhere on your development machine

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
81

For our auction application, we’ll need to define what data an Item should expect
to contain. We can define data structures in Elixir inside our modules
using defstruct. In the case of an auction Item, let’s initially keep track of the ID,
a title, a description, and at what time and date the auction should end. In your
preferred text editor, create a file named auction.ex and key in the following:
defmodule Auction.Item do
defstruct [:id, :title, :description, :ends_at]
end

As we briefly discussed in Chapter 2, structs in Elixir can be thought of as special


Maps. When we define our Item module (namespaced inside Auction), we also
define the structure of the data we’d like for it to contain with defstruct. If we
wanted those particular attributes to contain default values, we could have defined
those as well like this:
defmodule Auction.Item do
defstruct id: 0,
title: "default title",
description: "deafult description",
ends_at: ~N[2020-12-31 23:59:59] ❶
end

❶ The ~N you see here is what’s known as a sigil. Sigils start with a "~" and a letter. They represent
different things in Elixir, but this one is an easy way to create a NaiveDateTime. It is considered
"naive" because it doesn’t know about the concept of timezones.

For our implementation, though, we don’t want to include default values for our
data so let’s go with the first implementation. Let’s try out our new struct. In your
preferred terminal, navigate to your development directory and start up an IEx
session while also compiling our new source file. If we pass iex the -r flag and a
file name, it will compile that file and make it available in the session.
$ iex -r auction.ex ❶
Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10]
[hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> %Auction.Item{}
%Auction.Item{description: nil, ends_at: nil, id: nil, title: nil}

❶ You can see all the different available flags for iex with iex --help.

You can see that we now have the first building block of an auction item for our
application. In Listing 4.1, let’s get back into your iex session and try adding some
data to our new struct.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
82

Listing 4.1 Building our first Item

iex(2)> alias Auction.Item ❶


Auction.Item

iex(3)> book = %Item{


...(3)> id: 1,
...(3)> title: "Phoenix in Action",
...(3)> description: "Learn Phoenix with Manning's 'in Action' series",
...(3)> ends_at: ~N[2018-07-01 12:30:03]}
%Auction.Item{description: "Learn Phoenix with Manning's 'in Action' series",
ends_at: ~N[2018-07-01 12:30:03], id: 1, title: "Phoenix"}

iex(4)> book = %{book | title: "Book -- Phoenix in Action"} ❷


%Auction.Item{description: "Learn Phoenix with Manning's 'in Action' series",
ends_at: ~N[2018-07-01 12:30:03], id: 1, title: "Book -- Phoenix in Action"}

❶ In order to save our fingers some extra typing, we can alias Auction.Item so that we only have to
type Item from then on.
❷ We can modify information by using the special Map modifier of | as long as the key already exists in
the Map being modified.

4.1.2 Adding a fake database


Eventually, all the data for the items in our auction application will live in a
database. However, in these early stages of our application, we won’t be adding the
overhead or complication of a database. Instead, we’ll use an in-memory
"database" of our own creation. The difference between our implementation and a
real database is that once we exit our application, none of the changes we make to
our data will be persisted. While this obviously is not a solution for the long-term,
it does allow us to create a simple API of sorts in order to play with data as if it
were a real database.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
83

Figure 4.5. Our fake database will contain a static list of Items

As you’ll recall from the chapter introduction, our initial "database"


implementation needs a few things to do:
1. List all the Items in the database
2. Get a specific Item based on its ID in the database
3. Get a specific Item based on other defining attributes
Before we go and talk directly to our database, in order to keep the boundaries of
application and database clear, we should create an API of sorts to help keep them
separate. In the same file we were in before (auction.ex), add the following
module as shown in listing 4.2.

Listing 4.2 Auction module to help retrieve data from the database

defmodule Auction do
alias Auction.{FakeRepo, Item} ❶

@repo FakeRepo

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
84

def list_items do
@repo.all(Item)
end

def get_item(id) do
@repo.get!(Item, id)
end

def get_item_by(attrs) do
@repo.get_by(Item, attrs)
end
end

❶ Use this notation to alias several modules at once. This expands


to alias both Auction.FakeRepo and Auction.Item.

We will shortly also define a module called Auction.FakeRepo that will hold our
data for this particular implementation. Instead of
calling Auction.FakeRepo directly in each function, we can set our preferred Repo
at the top of the file as a module attribute (@repo FakeRepo). This will make it
easier to change in the future when we move to an actual database implementation.
When that happens, instead of changing every function’s call
from Auction.FakeRepo, we only have to change this one line to point to the new
real repo. If you need to change repos again in the future, it will also be very easy
to make that change with one line.

Module attributes
Module attributes in Elixir can serve a few different functions, but here (@repo) it is used as a
form of a constant value. When the module is compiled, the value of the module attribute is
read and inserted into any code that is referencing the attribute. Since it is compiled, it cannot
be set or changed at run-time.
Module attributes can also be used as file annotations such as documentation or as
temporary storage. To read more about module attributes and their uses, check out the Elixir
guides page on the topic. 16

Another question you may have after looking through Listing 4.2 is why are we
passing Item as the first argument to each function in @repo? While we currently
only have Items in our database, we’ll soon have other things like bids or users that
we’ll need to store and retrieve. When we pass Item in as the first argument, it lets
the repo know which database table (set of data) we are requesting.
Listing 4.2 shows a good way to isolate your business logic from your database
calls. You’ll see files like this used as a kind of standard in Phoenix — a border
between two different parts of your app that contain completely differing domain
knowledge. In this case, as you’ll see below in listing 4.3, the function names we

16
Elixir guides page about module attributes: elixir-lang.org/getting-started/module-attributes.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
85

use aren’t very different for the Auction module and our FakeRepo module. This is
mostly a product of the fact that we aren’t actually using a real database yet but are
attempting to model one that the Ecto package will later provide for us.

Figure 4.6 Auction.FakeRepo.all/1 and Auction.list_items/0 will be used to retrieve all


the Items

Until we bring in Ecto to get us a real database and repo, let’s continue on with
listing 4.3 and add our fake repo. Our fake repo will act like a database in that it
will contain a list of Items that we want to have up for sale. Beyond that, we’d like
to have a way to get to that data and manipulate it if necessary. Our goal with this
particular module is to act as our in-memory store of information that we are
calling our "database". First, we’ll define the list of Items that exist in our database,
then we’ll create the functions necessary to handle the function calls we created in
Listing 4.2.
As in the first listings in this chapter, we will be adding this module into the same
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
86

file (auction.ex). Later in the chapter, we will break the modules out into separate
files and talk a bit about project file structure.

Listing 4.3 Adding a fake repo

defmodule Auction.FakeRepo do
alias Auction.Item

@items [ ❶
%Item{
id: 1,
title: "My first item",
description: "A tasty item sure to please",
ends_at: ~N[2020-01-01 00:00:00]
},
%Item{
id: 2,
title: "WarGames BluRay",
description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35]
},
%Item{
id: 3,
title: "U2 - Achtung Baby on CD",
description: "The sound of 4 men chopping down The Joshua Tree",
ends_at: ~N[2018-11-05 03:12:29]
}
]

def all(Item), do: @items ❷


end

❷ The all/1 function will be called to return all the Item s in our "database". All it does is return
the @items module attribute…
❶ …which is a List of Items.

As before in Listing 4.2, we will be using a module attribute in order to store our
list of items as a constant that will be evaluated at compile-
time. Auction.FakeRepo.all/1 takes the list of items we provided in that attribute
and just returns it to the user. Note that we utilized pattern matching in our function
definition. This particular function will only be called if the first argument to
allis Item. We can then leave room for returning other types of data in the future.
You can imagine having all(User) and all(Bid) as our application grows.

What is a Repo?
You’ve seen the term Repo used enough by now that if you are not familiar with it, you are
really starting to wonder what it is. Very simply, the Repo (or repository) is a mapping to a data
store. In our case, the data store is our static @items module attribute but normally—and for
in the next chapter on—it maps to an actual database.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
87

The database is the component that actually stores the data. The Repo will be our
application’s gateway to the data inside the database. Our Repo will translate what we’d like
from the database from a defined API into "database speak". This is really neat because as
long as an adapter is available, our Repo can talk many different database "languages" but
the API for our application to talk to the Repo remains the same.

Now that we have a fake database with data, we can attempt to use it. Since we
wrote a function in Listing 4.2 to be a boundary between our application, let’s use
that. That way we can verify that the our modules are working well with each other
and also so we can get used to calling our boundary functions instead of working
directly with our repo. In Listing 4.4, we use this new fake database layer of our
application in iex. Whenever you modify a file and would like to have those
modifications inside an already-running session of IEx, you can run c
filename.ex to recompile it and redefine the module.

Listing 4.4 Using our new fake database

# ...continuing from our previous iex session


iex(5)> c "auction.ex"
warning: redefining module Auction.Item (current version defined in memory)
auction.ex:1

[Auction.FakeRepo, Auction.Item]

iex(6)> Auction.list_items
[%Auction.Item{description: "A tasty item sure to please",
ends_at: ~N[2020-01-01 00:00:00], id: 1, title: "My first item"},
%Auction.Item{description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames BluRay"},
%Auction.Item{description: "The sound of 4 men chopping down The Joshua Tree",
ends_at: ~N[2018-11-05 03:12:29], id: 3, title: "U2 - Achtung Baby on CD"}]

Tada! We can now list all the items in our "database". Let’s make it just a little bit
more useful. We’ll definitely want to do at least two more things before moving
on:
1. Get a specific Item based on its id
2. Get a specific Item based on other identifying information such as its title or
description
Let’s build those two things out in our FakeRepo.
4.1.3 Getting an Item by id
When we want to get a specific Item, we will most of the time know the id of that
Item. For example, a webpage request might be something
like myawesomeauction.com/items/8746 and 8746would be the id of the Item
loaded. What we need our finder to do is to loop through the List of @items and

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
88

find the one that has the id we are looking for.


Figure 4.7. Checking each Item’s id to find the one we are looking for

Thankfully, we can use Enum.find/2 for exactly this purpose. Enum.find/2 expects
two things to be passed in:
1. A collection of things to iterate over.
2. A function to call for each thing in the collection. The function should take one
argument and that will be the thing in the collection currently being examined.
def get!(Item, id) do
Enum.find(@items, fn(item) -> item.id === id end)
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
89

Figure 4.8. Breaking down Enum.find/2

Enum.find/2 will loop through each item in the collection until it finds one for
which the passed function returns true. Our function simply compares the id of
the item currently being examined with the id passed into the get!/2 function
itself. Here it is in use (don’t forget to recompile auction.ex with c
"auction.ex" before trying to use our new function). We’ll try using it directly
with the FakeRepo and then again with our boundary Auction module.
iex> Auction.FakeRepo.get!(Auction.Item, 2)
%Auction.Item{description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames BluRay"}

iex> Auction.get_item(2)
%Auction.Item{description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames BluRay"}

As expected, get_item/1 returns the Item that has the id of 2, which is what we
asked it for.
4.1.4 Getting an Item by other information
While we will know the id of the Item to look up a lot of times, we still need to
account for getting an Item by other identifying information. For example, what if
a user searches for an Item by title? Handling user queries can be a complex
subject, but we can account for exact matches with our a function. We’ll
create get_by/2 to handle finding an Item by a Map of matching information.
Before we add any code, let’s think about what it is we want to accomplish with
this search.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
90

1. Take each Item in the list one by one.


2. Compare the attributes of an Item to one the attributes we are looking for.
3. If that one attribute matches and we have another attribute we’re looking for, try
that one next.
4. If we have gone through all our attributes and they’ve all matched, we’ve found
the Item we’re looking for! Return that Item to the user.
5. If any attribute doesn’t match, we know that we haven’t found the Item we are
looking for and should move on to the next.
6. If there are no more Items to check, we know that none of the Items in our list
match all the attributes we were looking for. We’ll return nil to indicate that
nothing matched.
Figure 9 is a flow chart of the strategy of searching that we will implement.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
91

Figure 4.9. The flow chart get_by/2 uses to determine if it has found the Item

Now that we’ve decided on our search strategy, we can start adding some code.
Add the code in Listing 4.5 to your Auction.FakeRepo module.
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
92

Listing 4.5 Adding get_by/1 to Auction.FakeRepo


def get_by(Item, attrs) do
Enum.find(@items, fn(item) ->
Enum.all?(Map.keys(attrs), fn(key) ->
Map.get(item, key) === attrs[key]
end)
end)
end

I understand what you might be thinking: "WHAT?!". This is the most complex-
looking function we’ve seen yet but don’t let the nesting scare you off. If we can
peel the layers back one at a time, it is actually not that hard of a function to grasp.
Before reading further, try to understand on your own what this does. The names of
the functions you haven’t seen yet should give you good clues as to what is going
on.
OK, got an idea (or just want to get on with it)? Let’s peel it back.
• You’ve already seen Enum.find/2 in use in
our Auction.FakeRepo.get!/2 function. This time, our function that examines
each item in our @items list is just a bit more complex.
• Enum.all?/2 is a lot like Enum.find/2 in that it takes a collection of things and a
function to run on each of them. The difference is that instead of returning the first
thing that returns true, it runs through the entire collection until either the passed
anonymous function returns false or every run of the function has returned true.
Put another way, Enum.all?/2 returns true if, when passed every thing in the
collection, the provided function returned true; or false if even one thing
examined returned false. It essentially asks if all of every run of the function
provided can be evaluated to `true`.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
93

Figure 4.10. Enum.all?/2 asks if every iteration of the function is true

• Into Enum.all?/2 we pass all the keys of the attrs Map passed in to get_by/2.
This allows us to search for one thing (like %{title: "WarGames BluRay"}) or
multiple things at the same time (like %{title: "WarGames BluRay", id: 2}).

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
94

Figure 4.11. We iterate through all our Items until we find a match

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
95

• For each of those keys in map, we see if the examined item has that key and if it
does, if it matches the map 's value for the same key.

Figure 4.12. If all the attributes match, we have a winner!

Let’s use it in Listing 4.6.

Listing 4.6 Using Auction.FakeRepo.get_by/2 via Auction.get_item_by/1

iex> Auction.get_item_by(%{id: 2})


%Auction.Item{description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames BluRay"}

iex> Auction.get_item_by(
...> %{description: "A tasty item sure to please", id: 1}
...> )
%Auction.Item{description: "A tasty item sure to please",
ends_at: ~N[2020-01-01 00:00:00], id: 1, title: "My first item"}

Your current implementation of Auction.FakeRepo should mirror listing 4.7 (shown


here in its entirety).

Listing 4.7 Adding a fake repo

defmodule Auction.FakeRepo do
alias Auction.Item

@items [ ❶
%Item{
id: 1,
title: "My first item",
description: "A tasty item sure to please",
ends_at: ~N[2020-01-01 00:00:00]
},
%Item{

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
96

id: 2,
title: "WarGames BluRay",
description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35]
},
%Item{
id: 3,
title: "U2 - Achtung Baby on CD",
description: "The sound of 4 men chopping down The Joshua Tree",
ends_at: ~N[2018-11-05 03:12:29]
}
]

def all(Item) do
@items
end

def get!(Item, id) do


Enum.find(@items, fn(item) -> item.id === id end)
end

def get_by(Item, map) do


Enum.find(@items, fn(item) ->
Enum.all?(Map.keys(map), fn(key) ->
Map.get(item, key) === map[key]
end)
end)
end
end

4.2 We Stop at Item retrieval


So far, we have designed a way to retrieve Items from our "database" but we’ve
quickly come upon a limitation—we can’t add Items, we can’t update an Item, and
we can’t delete an Item. Those three things, along with the things we’ve
implemented this chapter (listing, getting by id, searching by attributes) are
fundamental concepts for a database. We could implement more fake database
functions to allow us to do those things (perhaps with an Agent 17 ) but that is
beyond the scope of this chapter.
Instead, in the next chapter, we will move from having all our code in one file to
having an actual Elixir application. Plus, we’ll learn how to bring in outside Elixir
packages to help make our code even better.

4.3 Summary
In this chapter you learned
• Phoenix is not your application, but just one entry point into it.

17
Check Agents out. They are amazing. hexdocs.pm/elixir/Agent.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
97

• Your application can have many various entry points, such as the web, hardware,
the command line, and many others.
• Because of the possibilities of various entry points, it is a good idea (and standard
practice) to try to keep your business logic separated and isolated as much as
possible. Don’t let things like computation get mixed in with things like the
workings of the database.
• Some nested enumerators can be intimidating when you look at them, but
breaking them down into a flowchart can make them seem very approachable.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
98

This chapter covers:


Elixir Application Structure

• Organizing separate Elixir code into a project


5
• Using the mix utility to manage your Elixir projects
• How to use hex.pm to utilize third-party tools and libraries

Up until now, we’ve been writing and using Elixir code in an IEx session or, as in
the case of Chapter 4, in a single file. The majority of your Elixir and Phoenix
projects will not be organized like this, however. As you application grows in
complexity, it becomes imperative that some sort of organizational structure is
implemented to keep things manageable.
In this chapter, we will be covering the structure of a typical Elixir application.
Along the way, we’ll utilize the mix utility to automate a lot of the tasks that would
be non-trivial if done manually. Finally, we’ll also utilize the hex package manager
to bring in third-party tools and libraries into our application. All of these things
will help us get our application set up in the right way before we tackle using a real
database in Chapter 6.

5.1 Moving From A Single File to an Application


When we left chapter 4, our Auction application so far consisted of a fake repo, an
API layer to access the data in our fake repo, and an Item struct that defined the
data structure of our auction Items. All that code—three modules—existed in a
single file. Once we start adding more functionality, that kind of project structure
will simply become unmaintainable. There are a number of things you could do
yourself to mitigate this issue. You could break up the modules into separate files.
This is a great idea on the surface but as you increasingly need code from one file
in a different file, you’ll soon run into a maze or web of interconnected files that all
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
99

depend on one another.


Fortunately for us, there is a standard directory structure for Elixir projects. As
seen in Figure 1, there are three main, top-level directories that tend to exist for
every Elixir application:
1. Code that exists for configuration goes into the config subdirectory
2. The bulk of your modules and business logic go into lib
3. Tests go into, of all things, test

Figure 5.1. The basic directory and file structure of an Elixir project

Along with the standard directories, you’ll also typically find a file named mix.exs.
This file can be considered to be the brain or mothership of your application. We’ll
be diving into this file in the next section.
While simple applications are typically structured in this way, we will be creating
multiple applications—one for the business logic that we’ve already been working
on and one for our Phoenix application. However, we’ll be creating another
skeleton application along with those two to tie them together. This kind of pattern
is called an "umbrella application".
5.1.1 Using mix to create a new application
You may be thinking, "Oh, great. Every time I want to start a new Elixir
application, I have to remember this standard structure." If you are indeed thinking
that, I’ve got some great news for you! You don’t have to remember that at all! All
you have to remember is mix. Like iex, the mix utility is installed for you when you
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
100

install Elixir. And, luckily for those of us who have to remember too many other
things, it has an excellent help system (again, just like IEx).
If all you remember is the command mix, you can figure out how to get the rest.
Listing 5.1 jumps directly into using the mix tool, even though we don’t know
anything else about it. Thankfully, it will tell us all the different things it can do for
us! I run mix in my terminal:

Listing 5.1 Letting mix tell us what it can do

> mix
** (Mix) "mix" with no arguments must be executed in a directory with a mix.exs
file

Usage: mix [task]

Examples:

mix - Invokes the default task (current: "mix run")


mix new PATH - Creates a new Elixir project at the given path
mix help - Lists all available tasks
mix help TASK - Prints documentation for a given task

You can see that the second example tells us how to create a new Elixir project!
That sounds helpful. But what if we want to know more? You can see from Listing
5.1 that it even tells you how to get more help. If we enter mix help new it will give
us all the help documentation for how to use that specific task (Listing 5.2).

Listing 5.2 Using mix help new to learn about creating a new Elixir project

> mix help new

mix new

Creates a new Elixir project. It expects the path of the project as argument.

mix new PATH [--sup] [--module MODULE] [--app APP] [--umbrella]

A project at the given PATH will be created. The application name and module
name will be retrieved from the path, unless --module or --app is given.

A --sup option can be given to generate an OTP application skeleton including a


supervision tree. Normally an app is generated without a supervisor and without
the app callback.

An --umbrella option can be given to generate an umbrella project.

An --app option can be given in order to name the OTP application for the
project.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
101

A --module option can be given in order to name the modules in the generated
code skeleton.

## Examples

mix new hello_world

Is equivalent to:

mix new hello_world --module HelloWorld

To generate an app with a supervision tree and an application callback:

mix new hello_world --sup

You can see from Listing 5.2 that there are a number of options we can specify
when creating a new Elixir application. If we wanted to create a new Elixir
application, we’d definitely want to use this tool as the first step. mix new will
generate not only the standard Elixir application directory structure, but also give
you some files that are starting points for your application.
Before we create an application for our Auction backend, let’s use the tool on a
throwaway project just to see how it works. Since the first option to mix new is the
path of the project as well as the application name, you’ll need to avoid most
special characters. Like in variable names, we’ll need to avoid using dashes but can
use underscores. If you are like me and prefer dashes in your project directories
instead of underscores, we can specify an alternate name for the application itself
(with --app) that utilizes underscores instead. Imagine you want to create a
Facebook replacement named FriendFace 18 . In a temporary directory somewhere,
run the following (Listing 5.3):

Listing 5.3 Using mix new

> mix new friend-face --app friend_face


* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/friend_face.ex
* creating test
* creating test/test_helper.exs
* creating test/friend_face_test.exs

Your Mix project was created successfully.


You can use "mix" to compile it, test it, and more:

18
Thanks to the show The I.T. Crowd for the name inspiration
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
102

cd friend-face
mix test

Run "mix help" for more commands.

You can see that not only did the mix new command create our directory structure,
but also gave us a README, a .gitignore file for ignoring files in our git repo if we
were to create one, a config file, a skeleton module for our friend_face application,
and even a test file. You can peek into each of these files and see that they are not
just empty files. They are files that have actual use as they are and are very helpful
as you are getting started. If you follow the instructions at the end of Listing 5.3
and run mix test in your project directory, you’ll even discover that it already has
a passing test!
After you’re done exploring your next million-dollar idea application, feel free to
delete the directory and all the files it generated for us. We won’t need them.
5.1.2 Generating our Auction umbrella application
Now that we’ve discovered a little bit about how mix works, let’s create an
application for our Auction site. We will use the mix new command like before
except this time we’ll want to do it in a non-temporary directory you use for your
projects. The first thing we need to generate is the umbrella itself. We will then
create an Auction application inside that umbrella.
Creating an umbrella application is very simple: we pass the --umbrella flag to mix
new. Let’s call our umbrella structure auction_umbrella to make it recognizably an
umbrella structure. I get Listing 5.4 in my terminal when I run that command.

Listing 5.4 Generating an umbrella application

> mix new --umbrella auction_umbrella


* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating apps
* creating config
* creating config/config.exs

Your umbrella project was created successfully.


Inside your project, you will find an apps/ directory
where you can create and host many apps:

cd auction_umbrella
cd apps
mix new my_app

Commands like "mix compile" and "mix test" when executed


in the umbrella project root will automatically run

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
103

for each application in the apps/ directory.

This kind of structure allows us to create sub-applications that are all contained
under the umbrella application. We don’t really need to modify anything it
generated at the moment, but the output does give us a good clue as to what we
should do next. All the sub-applications of an umbrella application are stored in
an apps directory (auction_umbrella/apps in this case). We can then cd into that
subdirectory and run mix new app_name to generate a sub-application.
We’ll name our application "Auction". Catchy, huh? Cd into
auction_umbrella/apps and type mix new auction --sup in your terminal. What
does the --sup do? It creates an application skeleton with a supervision tree in
mind. This won’t make much difference now, but will as we go on (we’ll finally
utilize that supervisor in Chapter 7). You should see output like Listing 5.5.

Listing 5.5 Generating the Auction application

> mix new auction --sup


* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/auction.ex
* creating lib/auction/application.ex
* creating test
* creating test/test_helper.exs
* creating test/auction_test.exs

Your Mix project was created successfully.


You can use "mix" to compile it, test it, and more:

cd auction
mix test

Run "mix help" for more commands.

The rest of the work we’ll be doing in this chapter will strictly be inside
the auction_web/apps/auction directory.
THE MAGIC MIX.EXS FILE
For any Elixir application, the mix.exs file is pretty magical. In it, you’ll define
things like the current version of your application, your application’s name, the
version of Elixir it runs on, any outside dependencies that your application requires
in order to run, and any additional applications or supervisors that also need to be
started when your application is started.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
104

If we take a peek inside the mix.exs file that our mix new task generated for us, you
can begin to see just how helpful that mix task is. Listing 5.6 shows what ours
looks like.

Listing 5.6 Our mix.exs file (some comments removed)

defmodule Auction.MixProject do
use Mix.Project

def project do
[
app: :auction,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.6",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.


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

# Run "mix help deps" to learn about dependencies.


defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag:
"0.1.0"},
# {:sibling_app_in_umbrella, in_umbrella: true},
]
end
end

Let’s further break down each of these sections.

What’s the difference between .exs and .ex files?


You may have noticed that some of the files we are working with have the extension .ex and
some have the extension .exs. What are the differences? When do you use each?
.ex files are for compiled code. When the you’d like to execute the code in a .ex file, Elixir
first needs to compile the code. This is not the case for .exs files. .exs files are script files
and are interpreted when they are executed (meaning they do not have to be pre-compiled).

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
105

Most of the time, we will be writing .ex files as we want all the benefits of compiled code
(compiler optimizations, speed, etc.). .exs files, since they have to be interpreted, are slower
to run (since they have to go through parsing, tokenization, etc.). They are, however, a flexible
choice when you don’t require compilation. For example, the mix.exs file in an Elixir project
and all test code files are .exs files.

project
The project function (shown isolated in Listing 5.7) defines the top-level details of
your Elixir application including:
1. The app name as an atom (auction), the current version of the application (0.1.0)
2. The Elixir version(s) our app will run on (~> 1.6 19 )
3. Configuring the application so that if it goes down either by failure or successful
shutdown, other applications that your application started as dependencies will
also be shutdown (this is set as true in the production environment by the return
of the comparison of the current Mix environment to the :prod atom.)
4. A list of dependencies. This is expecting a list of tuples containing external
package names and version numbers but for simplicity sake, it is set up by default
to rely on a private method defined later named deps. We will cover
the deps function shortly.

Listing 5.7 The project function in detail

def project do
[
app: :auction,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.6",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

There are actually many more options that can be set here for your application.
Elixir itself has a few more (which you can read about in it’s excellent
documentation page for Mix.Project 20). Other dependencies of your application
may have their own options that will need to be set here as well.
application
The application function (Listing 5.8) is a pretty simple one in terms of what is

19
The ~> means the following version number can be incremented by the last-given dot in the version. So in this case, we
could run versions 1.6 through 1.∞ but not versions before1.6 or 2.0 and later.
20
hexdocs.pm/mix/Mix.Project.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
106

generated, but the functionality it provides is big. In simple terms, it is what tells
the compiler that you’d like to generate an .app file for your application.
According to the documentation (which you can read by following the directions in
the comment about the function declaration # Run "mix help compile.app" to
learn about applications.):

An .app file is a file containing Erlang terms that defines your application. Mix
automatically generates this file based on your mix.exs configuration.

Listing 5.8 the application function in detail

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

Since an Elixir application really compiles down to Erlang code to run on the
BEAM virtual machine, we need to somehow get our Elixir code into Erlang. This
function provides additional instructions to the compiler about how to do that. The
most used options are regarding additional, external applications that need to be
started along with your application. Any application name (in :atom form) you
provide to extra_applications will be ensured to start before your application so
that if your application depends on any of those functions, it will be ready to accept
commands when your application needs them. By default, Elixir’s built-
in Logger application is started up to provide logging functionality.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
107

Figure 5.2. All of your files, plus all the dependencies are compiled into files that can run on the
BEAM VM

Elixir has the ability to know if third-party applications your application depends
on need to be started up. If they do, they will be started automatically without you
having to tell Elixir to explicitly do so. If an application needs to be included in
extra_applications, the README for the library will let you know. If it doesn’t
mention the requirement, you can bet that it either is started automatically or it
doesn’t need to be started at all.
Finally, the mod key is an application callback. Any module you specify in this list
(along with a list of arguments which is empty) will be called when the main
application starts. The callback expects Auction.Application.start/2 to be
defined. This is indeed the case for us since we generated the application with the –
sup flag.
deps
The final function that we see in our generated mix.exs file is deps. This is where
you will list all the external applications, packages, and libraries your application
depends on. You can see in Listing 5.9 that we currently rely on no external
packages.

Listing 5.9 Our empty deps function

defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
108

# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag:


"0.1.0"},
# {:sibling_app_in_umbrella, in_umbrella: true},
]
end

The format used to specify dependencies is the package name, plus the version
number(s) accepted, in a tuple (like {:package_name, "~> 1.0"}). For the version
requirements, there are a few different options you can specify. For more details,
check the Version documentation. 21 We will be using deps extensively the
coming sections.
Other options
There are a handful more options and functions you can use in your Mixfile that
aren’t generated in a skeleton application nor are we specifying in ours. If you’d
like more information on these options, check out the
22
Mix.Project documentation.

5.2 Organizing, Compiling, And Running Our New Application


For what comes next, I must apologize as it will be just a tiny bit of busy-work. In
the last chapter, I wanted to make sure it was obvious that you could define as
many modules as you wanted in a single file and they would all compile just fine.
It was also the easiest way to utilize multiple modules without a full-on Mix
application. But that means that we will need to break apart that file into three
separate modules. This is the only time in this book where we will cut and paste
code like this. OK, with that out of the way, are you ready?
We’ve used mix new auction to generate a skeleton application structure and
configuration for our Auction application and now we need to move all the code
we created in Chapter 4 from a single file containing multiple modules to separate
files per module. One of the cool things about Elixir is that you can name the files
whatever you want in whatever structure you want. This allows you to structure
your application as you see fit. However, the flip side to that is that unless you
decide on following a semi-strict self-rule regarding how you’re going to structure
your application files, it can quickly get out of control and you can lose your way.
5.2.1 Breaking Apart the Three Modules
If you’ll recall, we had three modules defined in auction.ex when we finished
Chapter 4:
1. Auction
2. Auction.Item
3. Auction.FakeRepo
21
hexdocs.pm/elixir/Version.html
22
hexdocs.pm/mix/Mix.Project.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
109

We therefore should create three different files—one for each module. Most of the
time, our application/library code should go in the lib directory that mix new
already generated for us. So we’ll start there.
The mix new task created a file in the lib directory of our application
named auction.ex. In that file, paste all the code that made up our Auction module.
You’ll notice that mix new auctiongenerated that file already and created a hello
function too. It is safe to overwrite all the contents of the generated file with our
module code. Listing 5.10 contains that module.

Listing 5.10 The new contents of lib/auction.ex is our Auction module

defmodule Auction do
alias Auction.{FakeRepo, Item}

@repo FakeRepo

def list_items do
@repo.all(Item)
end

def get_item(id) do
@repo.get!(Item, id)
end

def get_item_by(attrs) do
@repo.get_by(Item, attrs)
end
end

Figure 5.3. Auction.Item file location

For our Auction.Item module, we’ll need to create another new file. This time, a
file does not already exist for us to overwrite—we’ll need to create our own. While
you could create this file in the top level of the lib directory, it is standard practice
to match your directory structure to the namespacing of your module. What do I
mean by that? Item is namespaced underneath Auction in our module
name Auction.Item. Therefore, a good rule of thumb is to create
an auction subdirectory and have item.ex live in there.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
110

Paste the entirety of the Auction.Item module code info a file named
lib/auction/item.ex (or whatever you may have chosen). Listing 5.11 reflects
the contents of that file.

Listing 5.11 The contents of lib/auction/item.ex is our Auction.Item module


code

defmodule Auction.Item do
defstruct [:id, :name, :description, :ends_at]
end

Finally, we are left with our Auction.FakeRepo code. Like Auction.Item, we will
match the module namespacing with our directory structure. Paste the
Auction.FakeRepo module code from Chapter 4 into the file
lib/auction/fake_repo.ex, matching Listing 5.12. Note that another good rule of
thumb for file names is when you have a CamelCased module name, downcase the
name and use an underscore before the previously-capitalized letters. Therefore,
PhoenixInAction would become phoenix_in_action and FakeRepo becomes
fake_repo.

Listing 5.12 Auction.FakeRepo code lives in lib/auction/fake_repo.ex

defmodule Auction.FakeRepo do
alias Auction.Item

@items [
%Item{
id: 1,
title: "My first item",
description: "A tasty item sure to please",
ends_at: ~N[2020-01-01 00:00:00]
},
%Item{
id: 2,
title: "WarGames BluRay",
description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35]
},
%Item{
id: 3,
title: "U2 - Achtung Baby on CD",
description: "The sound of 4 men chopping down The Joshua Tree",
ends_at: ~N[2018-11-05 03:12:29]
}
]

def all(Item) do
@items
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
111

def get!(Item, id) do


Enum.find(@items, fn(item) -> item.id === id end)
end

def get_by(Item, map) do


Enum.find(@items, fn(item) ->
Enum.all?(Map.keys(map), fn(key) ->
Map.get(item, key) === map[key]
end)
end)
end
end

5.2.2 Compile and run!


Ok, thanks for sticking with me there. If you’ve followed along so far, you should
have a similar directory structure to Figure 5.4.
Figure 5.4. The files in our Auction application

But since Elixir is a compiled language, we’ll need to compile our application

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
112

before it can run. Thankfully, this is very easy.


COMPILING
Now that we’ve got it all organized, you may be wondering how we run it! In
Chapter 4, we compiled the file directly and brought it into an IEx session to play
with. Now that we have a full-fledged application, we can use the mix utility. For
example, in order to compile our application, we can issue the command mix
compile.

> mix compile


Compiling 3 files (.ex)
Generated auction app

The first time we run this, it will go through our entire application looking for .ex
files and compile them into something that can run on the Erlang VM (using
the mix.exs). You’ll notice that it compiled "3 files". Guess which three those
are—the three files we just created in the previous section! And since we got no
warnings during compilation, it tells us that it successfully generated our auction
application.
If you run mix compile again right away, you get no output from the compiler. This
is because Elixir’s compiler is smart enough to recognize that no changes have
been made since the last time we compiled and therefore nothing needs to be done!
In fact, it is smart enough to know not only that some files changed, but which files
changed. If a file didn’t change, it won’t be recompiled (unless it is affected by a
file that did change)! This will save you lots of time as you build up your app over
time.
RUNNING OUR AUCTION APPLICATION FOR THE FIRST TIME
So we now have a compiled application. How do we run it? At this point in time,
we have created no graphical interface to our application— only the code required
to play with our fake data through our API. Because of that, the only way we can
interact with our program at the moment is via IEx. However, we will be starting
our new IEx session a little differently than we have in the past. If you recall, in
Chapter 4, we would start IEx while requiring a specific file (our application code,
auction.ex). Now, we no longer have a single file. Instead, we have a Elixir Mix
application.
To start up an IEx session and require an entire Mix application to be brought in as
well, you can use the following command: iex -S mix.
> iex -S mix
Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10]
[hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
113

If we had not already compiled our application, it would compile here before
starting IEx. But since we previously did compile it, it starts right up and includes
all the files of our Auction application. Listing 5.13 shows an example of testing
out the API we created.

Listing 5.13 Trying out our compiled Auction application

iex(1)> Auction.list_items |> Enum.map(& &1.title)


["My first item", "WarGames BluRay", "U2 - Achtung Baby on CD"]

iex(2)> Auction.get_item_by(%{title: "WarGames BluRay"})


%Auction.Item{description: "The best computer movie of all time, now on BluRay!",
ends_at: ~N[2018-10-15 13:39:35], id: 2, title: "WarGames BluRay"}

It’s all working! We didn’t have to manually require any files, we didn’t have to
specify which files we were going to use, it all just worked! This is the "magic" of
an Elixir application. I say "magic" because when you move from using individual
source code files and getting caught in a mess of file requires and trying to get
everything working together to having something that just works right off the bat is
very refreshing. It again makes things very easy and is another example of how
Elixir makes developer happiness and productivity real concerns.

5.3 Using hex To Get External Dependencies


So now that we’ve gone through the configuration for our Auction application, we
now need to move on to declaring the dependencies. There are very smart Elixir
and Erlang developers out there and thankfully many of them have produced open-
source packages that add sometimes small, sometimes huge functionality to your
application. One such package we will eventually add to our application is Ecto.
Ecto describes itself as "A database wrapper and language integrated query for
Elixir". We will eventually need to move away from our FakeRepo and into a real
repo so we can allow real functionality in our application. Ecto is currently the de-
facto package to use when creating Elixir applications that need to talk to
databases. In fact, you have to explicitly tell Phoenix not to bring in Ecto if you
don’t need it when creating a new Phoenix project.
If you’ll recall from the section about the mix.exs file, our application keeps track
of its required dependencies in the deps function in that file. So far, we know we
require a pakcage called Ecto and it belongs in our mix.exs file. We are going to
need a little bit more information before we can do something actionable with this.
Hex is more than just a package manager—it also comes with nice mix tasks that
make using the package manager easy. For example, there is a great search tool.
Let’s say you know you’re going to need a package that makes rendering React.js
components easier in your Phoenix application but you don’t know any package
names. You can either go into a web browser and search the database through
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
114

Hex’s front end (at hx.pm) or use the mix task mix hex.search PACKAGE. In Listing
5.14, you can see the output from using the mix task.

Listing 5.14 Searching hex for a React.js package

> mix hex.search react


Package Version URL
reaxt 1.0.1 https://hex.pm/packages/reaxt
react_phoenix 0.5.0 https://hex.pm/packages/react_phoenix
lyn 0.0.16 https://hex.pm/packages/lyn
phoenix_components 1.0.2 https://hex.pm/packages/phoenix_components
react_on_elixir 0.0.4 https://hex.pm/packages/react_on_elixir
phoenix_reactor 0.1.0 https://hex.pm/packages/phoenix_reactor
reactive 0.0.1 https://hex.pm/packages/reactive
reactivity 0.6.0 https://hex.pm/packages/reactivity
elixir_script_react 1.0.2-react.15.6.1
https://hex.pm/packages/elixir_script_react
Phoenix_react 0.1.0 https://hex.pm/packages/phoenix_react

All of those packages listed above have something to do with the word "react".
"react" could be in the package name, in the description, or potentially other places
and they are ordered loosely by popularit
But sometimes, you do know what package you need and you just need to know
what the latest version number is. In those cases, I’ve found the mix task to be the
fastest way to retrieve that information. For example, we know we will need Ecto
in our application. Since we already know the package name, the only further piece
of information we require is the latest version number (unless we know of a
specific one already we want to depend on). In this case, let’s search for ecto with
the mix task. Listing 5.15 shows that search.

Listing 5.15 Searching hex.pm for ecto

> mix hex.search ecto


Package Version URL
ecto 2.2.7 https://hex.pm/packages/ecto

# ...many more results

We can see in Listing 5.15 that the latest version is 2.2.7. Unless you have a
compelling reason to use an older version of a package, it is generally a good idea
to use the latest. So we’ll depend on at least version 2.2.7 in our application.
To specify this version in our deps function in mix.exs, we specify the package
name and the version requirements. To specify the exact version number of 2.2.7,
our deps function would look like Listing 5.16:
Listing 5.16 Specifying our first dependency

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
115

defp deps do
[
{:ecto, "2.2.7"}
]
end

Listing 5.16 shows how to specify a dependency to a specific version requirement.


But sometimes there are other ways we’d like to handle the dependency versions.
In general, hex packages are suggested to use semantic versioning
(major.minor.patch). In the case of Ecto above, it is the major 2, minor 2,
patch 7 release. Major versions can have backward incompatible changes in them
and normally require some migration to happen in your usage of the package.
Minor versions typically contain new functionality but do not break existing usage.
Patch versions typically contain minor bug fixes and the like. So what if we want
to keep our Ecto package up to date but not have to worry about manually editing
the deps function every time we need to change the version number? There are a
few options in the version specification syntax that we can use.

Version examples
1) > 2.2.7 means give us any package as long as it is above version 2.2.7. This
does not include version 2.2.7 itself so in the case of Ecto as of writing, hex would not be
able to find a suitable version for the pckage.
2) >= 2.2.7 means give us any package equal to or above 2.2.7. This and the above
include any patch, minor, and potentially breaking major releases, so use this carefully.
3) < 3.0 means use any package found as long as it isn’t version 3.0 or above. This could
also mean that someone who comes along later (including you) would find that
version 0.0.4 can be used just as well as version 2.2.7. Use this with caution as well.
4) >= 2.2.7 and < 2.3.0 means any package that is from the major 2 minor 2 releases
as long as it is equal to or above 2.2.7.
5) ~> 2.2.7. Number 4 above is so common that a special symbol is used to denote this
kind of requirement. ~> MAJOR.MINOR.PATCH means use any version that is beyond the
PATCH version but not incrementing the MINOR version. ~> MAJOR.MINOR means take
any MINOR or PATCH version up to the next MAJOR version.

Regardless of the version requirements, hex will attempt to fetch the latest, most
recent package version that meets the requirement(s) specified. With that in mind,
let’s make sure to have hex include any bug fixes in the version 2.2 minor branch
by using the ~> 2.2.7 format. Listing 5.17 shows what your deps function should
look like.

Listing 5.17 Our newly-specified dependency list

defp deps do
[
{:ecto, "~> 2.2.7"}
]
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
116

While Ecto is an important part of our application because it provides a wrapper


around a database, it does not speak to the database directly. In order to do so, Ecto
requires an adapter specific to the database that you’d like to use. So why not use
the adapter directly? Ecto provides a large range of utilities and functions that
make working with a database much easier and without a lot of the boilerplate code
that is usually necessary. And since we are writing code that Ecto then translates
into database-speak, we can actually typically move from one database to another
without having to change much (if any) of our code.
In this book, we will be using the PostgreSQL database and so will therefore be
using the PostgreSQL adapter. The vast majority (if not all) of the code we will be
writing will work fine—as written—with any of the other Ecto adapters. There may
be small exceptions to this (mostly during setup of the adapter itself), but the fact
that the databases are so easily interchangeable is one of the great things about
using Ecto.

Table 5.1. Ecto database adapters

Database Ecto Adapter Dependency


PostgreSQL Ecto.Adapters.Postgres postgrex
MySQL Ecto.Adapters.MySQL mariaex
MSSQL MssqlEcto mssql_ecto
SQLite Sqlite.Ecto2 sqlite_ecto2
Mnesia EctoMnesia.Adapter ecto_mnesia

Since we are using Postgres, modify your deps function in mix.exs to include the
dependency (postgrex) like in Listing 5.18. If you’d rather use a different
supported database for your application, be sure to use the correct adapter.

Listing 5.18 Our newly-specified dependency list

defp deps do
[
{:ecto, "~> 2.2.7"},
{:postgrex, "~> 0.13.3"}
]
end

5.3.1 Pulling in our dependencies


Now that we have the dependencies specified, we need to go get them and bring
them into our application. We do that in Listing 5.19 by using, you likely guessed
it, a Mix task—mix deps.get. When you execute that task in your terminal, it will
go query hex.pm regarding the latest applicable versions of the dependencies that
you specified. It also does the job of fetching theirdependencies so you don’t have
to worry about manually ensuring a long line of dependency requirements are met.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
117

Listing 5.19 listing name

> mix deps.get


Running dependency resolution...
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 postgrex (Hex package)
Checking package (https://repo.hex.pm/tarballs/postgrex-0.13.5.tar)
Fetched package
* Getting ecto (Hex package)
Checking package (https://repo.hex.pm/tarballs/ecto-2.2.10.tar)
Fetched package
* Getting decimal (Hex package)
Checking package (https://repo.hex.pm/tarballs/decimal-1.5.0.tar)
Fetched package
* Getting poolboy (Hex package)
Checking package (https://repo.hex.pm/tarballs/poolboy-1.5.1.tar)
Using locally cached package
* Getting connection (Hex package)
Checking package (https://repo.hex.pm/tarballs/connection-1.0.4.tar)
Using locally cached package
* Getting db_connection (Hex package)
Checking package (https://repo.hex.pm/tarballs/db_connection-1.1.3.tar)
Fetched package

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
118

Figure 5.5. hex manages the sometimes complex relationships between your apps'
dependencies

The output you see is Hex fetching those required packages and putting them into
the deps directory of your application. The next time you compile your application
(whether explicitly via mix compile or by starting your application like iex -S
mix), those dependencies will be compiled into your application
for your application code to take advantage of.
We’ll be diving more into the usage of Ecto in the next chapter, but to demonstrate
how we can use external dependencies with little fuss, let’s temporarily add
the UUID package to our applications dependencies. Add the dependency
requirement to your mix.exs file as in Listing 5.20.

Listing 5.20 Temporarily adding UUID to our dependencies

defp deps do
[
{:ecto, "~> 2.2.7"},
{:postgrex, "~> 0.13.3"},

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
119

{:uuid, "~> 1.1.8"}


]
end

Be sure to also run mix deps.get again to fetch the newly added dependency. Now
let’s use it in our application’s environment via an IEx session. UUID is a package
that allows you to easily generate Universally Unique IDentifiers. We will simply
test it’s ability to do so within our own application’s environment in Listing 5.20
by using it’s uuid4/0 function to generate a version 4 UUID. We could even use it
to generate auction titles for us.

Listing 5.20 Using the UUID package in our auction application

> iex -S mix


# ... likely lots of code compilation output

iex(1)> UUID.uuid4
"40a6eb21-4c85-46ac-a550-e18130187aee"

iex(2)> %Auction.Item{title: UUID.uuid4}


%Auction.Item{description: nil, ends_at: nil, id: nil,
title: "592b2b0b-5f9e-4c74-91d9-478bd2ca1d9b"}

Since the purpose of UUIDs is to be "universally unique", your output will be


different than mine was above. However, the formatting will be the same and it
will be a valid UUID string. It works!
Because we are done with our little experiment, we no longer need the UUID
package. How do you get rid of once-required dependencies that are no longer
needed? It’s actually very simple. Simply remove it from the deps/0 function in
your mix.exs file (Listing 5.21).

Listing 5.21 Our deps function with UUID

defp deps do
[
{:ecto, "~> 2.2.7"},
{:postgrex, "~> 0.13.3"}
]
end

Once you’ve done that, you can again run mix deps.get and it will update
your mix.lock file which keeps track of all your dependencies. But if you look in
your deps folder for your project, you will still see a directory/folder for uuid. If
you’d like to get rid of that, you can simply manually delete it from the directory or
you can use the mix deps.clean uuid command in your terminal. It will determine
that it is no longer needed and remove the package’s code from your hard drive.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
120

5.4 Summary
In this chapter you learned
• The majority of Elixir projects aren’t contained within a single file, but within
multiple files within an application structure.
• Use mix new to start a new Elixir project. That single task will generate the initial
folder structure and files to get you started.
• The mix.exs file contains important information regarding the configuration of
your application.
• Hex.pm is the Elixir package manager and has many helpful third-party modules
and applications to help you create your application. Your application’s package
dependencies are stated in the mix.exs file.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
121

This chapter covers:


• Configuring your environment to use Phoenix
Bring in Phoenix
6
• Creating a new Phoenix project inside our umbrella app
• Using our Auction business logic in our Phoenix project

Up to this point, the flashiest thing we have to look at for our Auction application
is IEx. While IEx does the job, is full-featured, and generally looks nice, the UI
isn’t going to raise millions of dollars in seed money for your auction start-up. In
order to get users on our site and bids being made on the Items in our database,
we’ll need to get a web interface so that they can interact with the data.
It’s time to bring in Phoenix.
The first thing we want to do with Phoenix (and what we’ll be covering in this
chapter) is for it to list the Items in our database. Creating, editing, and deleting the
Items and bidding on the Items will all come later. By the end of this chapter, you
should be able to get something like Figure 1 in your web browser.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
122

Figure 6.1. Listing Items from our Auction’s fake repo

6.1 Installing Phoenix On Your System


The first thing we’ll need to do to get going with our Phoenix application is to
install Phoenix itself. If you’ve followed along with the chapters so far and with the
prerequisites, you should already have Elixir 1.5 or later installed on your system
as well as the hex package manager tools.
The most up-to-date installation instructions are always found in Phoenix’s
documentation 23 , but if you have all the prerequisites, you should be able to
type mix
archive.installgithub.com/phoenixframework/archives/raw/master/phx_new.ez i
n your terminal to install the latest version of Phoenix.
You will also need node.js, which you can find instructions for installing on the
node.js download page 24 or in the Phoenix documentation. 25 You will need
version 5.0.0 or greater.
If you have installed Phoenix correctly, you should now see some entries for mix
phx.? in the output of mix help (like in Listing 6.1).

Listing 6.1 Our new Phoenix mix tasks

> mix help | grep phx

mix local.phx # Updates the Phoenix project generator locally


mix phx.new # Creates a new Phoenix v1.3.1 application
mix phx.new.ecto # Creates a new Ecto project within an umbrella project
mix phx.new.web # Creates a new Phoenix web project within an umbrella
project

23
hexdocs.pm/phoenix/installation.html#phoenix
24
nodejs.org/en/download/
25
hexdocs.pm/phoenix/installation.html#node-js-5-0-0
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
123

These are some of the mix tasks we will be using while we are building our
Phoenix application. For now, though, we are keeping it incredibly simple.

6.2 Creating A New Phoenix Application


Once you’ve verified that Phoenix is installed on your system, let’s ask it to create
for us a new, blank Phoenix project. If you look at the output of Listing 6.1 above,
you will see the mix phx.newtask—that sounds like the one we want but take a
closer look at the last option. Since we’ve been building our application as an
umbrella application, we can generate a new project within that application. As
we’ve discussed previously, you can ask mix tasks for help so you can know how
to use them. In your terminal, type mix help phx.new.web. You should see output
similar to Listing 6.2.

Listing 6.2 the output of mix help phx.new

mix phx.new.web

Creates a new Phoenix web project within an umbrella project.

It expects the name of the otp app as the first argument and for the command to
be run inside your umbrella application's apps directory:

$ cd my_umbrella/apps
$ mix phx.new.web APP [--module MODULE] [--app APP]

This task is intended to create a bare Phoenix project without database


integration, which interfaces with your greater umbrella application(s).

## Examples

mix phx.new.web hello_web

Is equivalent to:

mix phx.new.web hello_web --module HelloWeb

Supports the same options as the phx.new task. See Mix.Tasks.Phx.New for
details.

The Phoenix/web portion of our application will not be using a database directly.
Why? Because we want to keep our domain logic separate from our web interface.
All the database interactions for our Items will be handled in the Auction
application we started in Chapter 5. Since that is the case, we will not need Ecto in
this application.
Figure 2 shows what your current umbrella application directory listing looks like.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
124

Figure 6.2. Our umbrella app directories before we create a Phoenix app

To create the application, navigate to the apps directory of


your auctionumbrella umbrella application, and run
> mix phx.new.web auction_web

You will see a lot of output scroll by as the mix task generates skeleton files for
your application. Once those files are created, you are greeted by a prompt asking
if you’d like to Fetch and install dependencies? [Yn]. You can go ahead and
type Y (or just hit return) and it will fetch all the dependencies you’ll need for our
Phoenix application. Again, more text will scroll by as your dependencies are
fetched from hex.pm.
6.2.1 Running our server for the first time
Once your dependencies are fetched, you are finally greeted with some good news
(as in Listing 6.3).

Listing 6.3 Your Phoenix application is ready!

We are all set! Go into your application by running:

$ cd auction_web

Start your Phoenix app with:

$ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
125

$ iex -S mix phx.server

We do want to start our application, so let’s follow their suggestion and go into our
new auction_web directory and run the mix task to start our server (mix
phx.server). As soon as you do so, you’ll see yet more debug text scroll by as your
application is compiled and the server is started up. As soon as you see something
like Listing 6.4, you’re serving webpages!

Listing 6.4 Your server is up and running

[info] Running AuctionWeb.Endpoint with Cowboy using http://0.0.0.0:4000


20:15:09 - info: compiled 6 files into 2 files, copied 3 in 970 ms

Now for the moment of truth! Fire up your favorite web browser and navigate
to 0.0.0.0:4000. You should see something similar to Figure 1. You’re now serving
up web pages through Phoenix on your computer!

What is 0.0.0.0:4000?
You may be used to entering domain names into your web browser, but numbers and colons
may be foreign to you. So what does this address (0.0.0.0:4000) mean?
The address can be broken down into two sections:

1) The IP address
2) The port number

The IP address is the address of the computer that is hosting the content. When you enter a
domain name into your browser, that domain name is actually like an alias for an IP address
which your browser actually calls. 0.0.0.0 is the IP address of your local computer.
The port is like the tunnel that the connection uses when making requests. The Phoenix
web server listens for connections on port 4000, so we make our browser go there explicitly.
When you don’t enter a port number, a browser uses port 80 by default for unsecure http
traffic.
Put the two together, and you have IP_ADDRESS:PORT, or 0.0.0.0:4000 in our case.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
126

Figure 6.3. If everything has gone correctly, this is what you’ll see—a webpage being served up
on your local computer through Phoenix

In order to stop the server, you can hit CTRL-C twice in the terminal that is running
the server.

6.3 Listing Items From Our Fake Repo


So you now have a running Phoenix web application but it’s not exactly going to
take over the world. For starters, there are no auction items listed! All we are
seeing now is the placeholder stuff that the mix phx.new.web mix task generated for
us. While it’s kind of exciting that we have a working web application, I, for one,
want more. Let’s list the items that we have currently up for auction. Figure 4
shows what we’ll see after we’re done with this chapter—a list of Item titles and
their descriptions.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
127

Figure 6.4. Listing Items from our Auction’s fake repo

If you have been following along with us in Chapters 4 and 5, you’ll have built an
Auction application that will contain all the business logic of our site. When we left
it, it was using a fake Repo to serve up hard-coded items. But the nice thing
about how we created it is that we don’t care what repo it uses or where it gets its
items or anything about its logic—we just want the items. This is that point where
having strong boundaries between your interface (like a Phoenix web application)
and your business logic has huge benefits. As long as our business logic provides
us an API to use to get the information we are after, let it decide where and how to
get the data. We want our web interface to be as naive as possible about the inner
workings of the business logic.
We did build a
simple API to get the items from our database:
Auction.list_items(). We can bring in that other application and use it in this
application. How can we do that? Specify it as a dependency in our mix.exs file!
The mix.exs file contains a function named deps that contains the list of
dependencies for our application. Right now, it contains the default dependencies
for a Phoenix application generated with the phx.new.web generator.
All we need to do is tell this web application about our Auction application. A
dependency declaration typically contains the name of the application required,
plus the version number(s) that would satisfy our dependency. But there are other
ways you can declare a dependency. One of those ways is via the path option to
direct it to a directory machine; another via the github option to specify a git repo
on Github. Instead of a version, we can tell it where to find the application we
depend on. We’ll use that to bring in our Auction application. Yet another option is
to tell it that it is available as another app within the same umbrella. This last
scenario is the one we have going on, so we’ll use the in_umbrella option.
Add {:auction, in_umbrella: true} to the list of dependencies (don’t forget the
comma at the end of the line above it if you are adding it to the end of the list). See
Listing 6.5 as a guide. Once we have added that dependency, we can now use
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
128

our Auction module in our new AuctionWeb Phoenix application inside the
umbrella.

Listing 6.5 The default list of dependencies

defp deps do
[
{:phoenix, "~> 1.3.1"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_ecto, "~> 3.2"},
{:phoenix_html, "~> 2.10"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:auction, in_umbrella: true} ❶
]
end

❶ This is the line we added.

6.3.1 Modifying the Controller and Template


In order to see the list of Items in our fake repo, we’ll need to modify the controller
and the view template. First, in the controller, we need to store the result of
the Auction.get_items() function call in a variable, then pass that to the view
template. Then, in the template, we need to loop through that list of items and
display information about each one.
THE CONTROLLER
If you are wondering which controller is being used to serve up the page that you
see when you navigate to 0.0.0.0:4000, you can figure that out in a couple different
ways.
1. Open up auction_web/lib/auction_web/router.ex. In there, you can see the the
root route ("/") is handled by AuctionWeb.PageController index.
2. Inside the auction_web directory, run mix phx.routes in your terminal. The
output of that is simply page_path GET / AuctionWeb.PageController :index,
which indicates the only route being handled right now is "GET /" and it is being
routed to AuctionWeb.PageController index.
We aren’t going to do anything super fancy in this chapter, so we’ll go ahead and
re-use the controller that the Phoenix generator made for us which is
that AuctionWeb.PageController we saw above. That controller was generated for
us at auction_web/lib/auction_web/controllers/page_controller.ex. If you open
that up, you’ll see Listing 6.6—a minimally-defined controller.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
129

Listing 6.6 The AuctionWeb.PageController

defmodule AuctionWeb.PageController do
use AuctionWeb, :controller

def index(conn, _params) do


render conn, "index.html"
end
end

You can see that the only function defined in the controller right now is that index
function that the root route points to. In the index function, we’ll need to do two
things.
1. Get the list of Item s, binding it to a variable; and
2. Pass that list to the view template so we can render the Items.
A controller’s functions are just like any other Elixir functions definitions—you
can call external module’s functions, store the results of those in a variable, and
transform data. We wrote our Auction module’s public-facing API so that we can
easily get a list of Items with Auction.list_items/0. We’ll use that function and
capture the result. Our modified index function looks like Listing 6.7.

Listing 6.7 Capturing the list of Items

def index(conn, _params) do


items = Auction.list_items() ❶
render conn, "index.html"
end

❶ Our addition

We now have the list of Item s in the items variable so step 1 is done. Step 2 is to
pass the list to the view template. The second line of the index function is a call
to Phoenix.Controller.render/2 and it takes two parameters: the conn which is
the Plug.Conn struct that is passed through the application from initial connection
through rendering the view, and the template name Phoenix should render for this
route ("index.html"). Figure 5 gives an overview of how the group of items moves
from a request from the controller, through the Auctionmodule, to
the Auction.FakeRepo module, and then back to the controller to be finally passed
off to the view/template.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
130

Figure 6.5. The flow of items from our fake repo to the view/template

If you are wondering why the generated code in the controller calls render directly
instead of its full name of Phoenix.Controller.render, take a look at line 2. It
reads use AuctionWeb, :controller. That line does a whole bunch of stuff behind
the scenes, but the thing we’re interested in is the fact that it calls import
Phoenix.Controller. That allows us to use any Phoenix.Controller function in our
module without having to type the full name.
Inside Phoenix.Controller, there is also a `render/3 which accepts a third
parameter: assigns (variables) to be passed through to the view. All we need to do
to utilize this other renderfunction is tack on our items list.

Listing 6.8 Passing items to the view template

def index(conn, _params) do


items = Auction.list_items()
render conn, "index.html", items: items ❶
end

❶ Our addition.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
131

Now the view has access to our items through a @items variable.
THE TEMPLATE
The final step for rendering our list of Items in the browser is to actually utilize the
@items variable that we set up in the controller. If you’ll recall, the second
parameter of the Phoenix.Controller.render/3 function on the last line of index/2
is "index.html". That defines the template Phoenix will use to render the web page.
Phoenix will look for a file named "index.html" in the page (for PageController)
subdirectory of the templates directory. The full page of the template file will be
auction_umbrella/apps/auction_web/lib/auction_web/templates/page/index.htm
l.eex.

This file is an .eex file which means it will be preprocessed by Phoenix before the
final HTML is output. This means we can use some Elixir inside the template file
itself. Everything inside <%=and %> tags will be processed by Elixir and the result
rendered in its place. You can also enclose Elixir code within <% and %> if you
don’t need to render the results.
If you open up the index template file, you’ll see some straight HTML that
provides the "Welcome to Phoenix" banner and links to resources and help. We can
safely delete all this HTML and replace it with our own. For our purposes, a simple
unordered list (<ul>) will be enough to list our Items. We can open up the
unordered list, but we’ll still need to loop through our list of Items and output a list
item (<li>) for each entry.
There is an idiomatic way to render each item in a list like this—for. for is a
"comprehension". According to the docs, "comprehensions allow you to quickly
build a data structure from an enumerable". Figure 6 has a bit of a breakdown on
the portions of the for comprehension as we will be using it.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
132

Figure 6.6. A breakdown of the for comprehension

The full documentation 26 contains some pretty neat examples and shows how
useful for can be, but we will use it pretty simply. Listing 6.9 shows how we can
use for to loop through the Items in @items and output a <li> tag for each one.

Listing 6.9 Using the for comprehension in index.html.eex

<ul>
<%= for item <- @items do %>
<li>
<strong><%= item.title %></strong>: <%= item.description %>
</li>
<% end %>
</ul>

This takes our collection of @items, takes each one at a time, and binds the
currently-considered item in item inside the do/end block. Inside that block, we
render an opening <li> tag, render the title of our item with <%= item.title %>
inside a <strong> HTML tag, then also render the description of our item with <%=
item.description %>. Remember, anything inside the <%= %> tags will be evaluated
as Elixir code and the result will be rendered. This allows us to get data from the
database, transform the data in any way necessary, then render what we need.
If you start your server back up (if you killed it earlier) with mix phx.server in the
top level of your auction umbrella application and then point your browser
26
hexdocs.pm/elixir/Kernel.SpecialForms.html#for/1
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
133

to 0.0.0.0:4000 again, you should see a list of your own like figure 7.
Figure 6.7. Listing Items from our Auction’s fake repo

Figure 8 shows a breakdown of how the listing is generated.


Figure 6.8. A breakdown of the list of items

You’ll notice that there are some things on the web page that we didn’t add. In
particular, there is a large "Phoenix Framework" banner image and some baseline
css/styles. If you remember back to Chapter 3, we briefly introduced the idea
behind the layout template and the page template. We edited the page template in
this chapter, but the layout template wraps every page template. The banner and the
rest of the wrapping HTML are contained in a "layout" template
named app.html.eex. We’re not going to cover it here, but if you’d like, go ahead
and take a peek inside that file to see how it works.
In the next chapter, we’ll bring in a real database and start persisting items into it.

6.4 Summary
In this chapter you learned
• mix phx.new generates a brand new Phoenix application
• mix phx.new.web generates a new Phoenix application inside an existing umbrella
application

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
134

• Use mix phx.server to serve your Phoenix application locally at 0.0.0.0:4000


• Controllers are where you set up your application’s state in order to correctly
render what needs to be rendered to the user
• Templates contain the HTML and Elixir code that is processed to send back to the
user to view in their web browser

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
135

This chapter covers:


Being Persistent with a Database

• Configuring Ecto to use a real database in our Application


7
• Using Ecto to query the database for Items
• Using Ecto to insert new Items into the database, query the database for Items, and
delete Items from the database

Our Auction application is at a point where we have set up an API to query for
Items in a fake database and we now know how to bring external package
dependencies into our application. Last chapter, we finished the beginning phases
of readying our application for real database usage by bringing in Ecto and
Postgrex (or a different database adapter based on your needs).

7.1 FakeRepo Isn’t Going To Last Long


If you’ll recall, we have set up our Auction application to use a "fake" repo or
database for the time being. The reason we did that was to not introduce too much
complexity at the beginning, as well as to provide us some flexibility while we
built up a small API for querying Items. The upside was that it was relatively quick
to set up, required no external dependencies, and was fast. The downsides are that
it doesn’t get us much further than reading a static list of Items for our application.
If we eventually want a true data-driven web application, we’ll need the ability to
do complex queries as well as insert new Items and update existing ones.
In this chapter, we will utilize Ecto and get rid of our old, fake database and move
to a real database. Because of that, before we begin this chapter, there are a few
prerequisites that need to be taken care of outside of this book.
1. You need to have a database installed in your local dev environment. I am using
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
136

PostgreSQL. There are other options available in Ecto if you’d rather use them
(like MySQL, MSSQL, etc.). Since Ecto is a package built to provide abstractions
away from SQL-like language, there may be database-specific gotchas for your
database of choice. Check the Ecto documentation to see if your database has any
specific issues. 27
2. Once the database is installed, you need to know the correct way to access it. This
involves the database address (typically localhost or 127.0.0.1) as well as the
port number (if it differs from the database’s default port).
3. Finally, you’ll need to have a database user and password either created
specifically for our Auction application or have one already available.

7.2 A Quick Intro To Ecto


Ecto does more than just talk to databases. It actually provides a unified language
for talking to multiple different kinds of databases—even simultaneously. It
provides an easy way to specify module relationships, query databases, provides a
way to track changes throughout the lifecycle of a database request, and allows you
to group multiple queries into a single transaction so that if one query fails, the rest
of the queries can be rolled back.
It provides a way to describe the way our structs will handle data and map them to
specific database tables. It provides migrations so that you can track how a
database’s structure changes over time and allows you to roll up or down any
connected database to match the required structure. It provides validations both
module-side and database-side to ensure you don’t have orphaned or bad data in
your database.
There are obviously many things that Ecto does (and does well!) and while we
likely won’t touch on every single one of those things in this book, the best way to
learn is to dive in and get our hands (code?) dirty.

7.3 Configuring Ecto


If you haven’t already specified Ecto as a dependency in your application (like we
did in Chapter 5), you’ll need to make sure you do that first. As a quick review,
the deps function in your mix.exs file should look similar to Listing 7.1.

Listing 7.1. Specifying Ecto and Postgrex as dependencies

defp deps do
[
{:ecto, "~> 2.2.7"},
{:postgrex, "~> 0.13.3"}
]
end

27
github.com/elixir-ecto/ecto
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
137

I am using PostgreSQL as I write my version of Auction, so I will be sure to


include postgrex as a dependency along with ecto. Refer to Table 1 if you are
using a different database to make sure you have the correct adapter specified.

Table 7.1. Ecto database adapters

Database Ecto Adapter Dependency


PostgreSQL Ecto.Adapters.Postgres postgrex
MySQL Ecto.Adapters.MySQL mariaex
MSSQL MssqlEcto mssql_ecto
SQLite Sqlite.Ecto2 sqlite_ecto2
Mnesia EctoMnesia.Adapter ecto_mnesia

Once you have ensured you have the correct dependencies listed, run mix
deps.get in your terminal to fetch the packages from hex.pm.

In order for Ecto to work with our database, we will need to give it some
information such as the database name, the username and password it can access
that database with, and the database adapter we will be using. Application
configuration like that is typically done in the config/ directory and more
specifically the config.exs file contained there.
You may (or may not) be surprised to learn that you already have
a auction_umbrella/apps/auction/config/config.exs file in your version of our
Auction application. How did it get there? Well, it was created along with the rest
of the standard files and directories for our application when we used the mix
new command-line script. If you open up that file, you’ll notice that almost nothing
is in the file apart from comments. However, those comments can be very helpful
as you learn what can be configured and how to go about not only configuring, but
also reading those configurations in your application.
For Ecto, the reading and utilizing parts of the config are already taken care of for
us—we just need to tell Ecto about our local database environment. Specifically,
there are three initial things we need to let Ecto know:
1. What Repo(s) we will have in our application.
2. How to access each of the Repos we specified in #1.
3. Minimal setup for the Repo.
As described in the comments in config.exs we do that with the config function.
There are two different versions of config—config/2 and config/3. We will be
using both. config/2 requires the name of our application (:auction) and key/value
pairs we’d like to configure.
For #1 above, we will tell our application that the name of our repo will be
Auction.Repo. Ecto can handle multiple repos simultaneously and for that reason it
expects a List as its value. Add Listing 7.2 to your config.exs file.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
138

Listing 7.2. Letting Ecto know which Repos we will have in our application

config :auction, ecto_repos: [Auction.Repo]

config/3 requires the name of our application (:auction), a key to store the
configuration under, and key/value pairs of configuration. We use config/3 when
we tell Ecto how our Auction.Reporepo will be able to communicate with our
database. Listing 7.3 shows the basic values that Ecto requires in config.exs.

Listing 7.3. Configuring Auction.Repo

config :auction, Auction.Repo,


database: "auction",
username: "postgres",
password: "postgres",
hostname: "localhost",
port: "5432"

The values above should be pretty self-explanatory and match up with what was
described in the prerequisites above. Plug in the values that work for your local
database. Also note that I am using PostgreSQL so the adapter for PostgreSQL is
Ecto.Adapters.Postgres. If you require a different database adapter, refer to Table
1.
Finally, we need to create a file that will house the code for our Repo. This is
super-simple as Ecto provides almost all the functionality you will need when you
use Ecto.Repo. All we need to do in our module is use Ecto.Repo and specify the
name of our application (:auction). In a file named
auction_umbrella/apps/auction/lib/auction/repo.ex, enter the code as found in
Listing 7.4. Naming the module Auction.Repo matches the Ecto configuration used
in Listing 7.2.

Listing 7.4. Setting up the Auction.Repo file

defmodule Auction.Repo do
use Ecto.Repo,
otp_app: :auction,
adapter: Ecto.Adapters.Postgres
end

By including use Ecto.Repo, opt_app: :auction in our module, we are benfiting


from a number of functions that Ecto brings in for the module that we don’t have to
define ourselves. It makes it so that boilerplate code is kept to a minimum. That’s it
on the Elixir side of things! You are now ready to use Ecto.
7.3.1 Using Ecto’s mix Tools to Set Up Your Database
Believe it or not, you have already provided Ecto the minimum amount of
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
139

knowledge it needs to start interacting with your system and application. The first
thing we’ll want Ecto to do for us is actually create the database that we specified
when we configured Auction.Repo in config.exs (i.e. database: "auction"). In
order to do that, we’ll use the mix tasks that Ecto provides. After you have set up
your database with a user as specified in your config file (i.e. username:
"postgres", password: "postgres"), and that user has the ability to create a
database, you can run the ecto.create mix task as in Listing 7.5.

Listing 7.5. Using Ecto’s mix task to create our database

> mix ecto.create


The database for Auction.Repo has been created

If you received the above message when you ran that command, you are in
business! Your application can connect to the database and interact with it
successfully.

7.4 Preparing Auction To Use The Database


Now that we have created the database itself, we need to create the structure of our
database. How will the information in the database be structured? What will it look
like? What kind of data will we be storing? This information is provided by us to
Ecto as a "schema".
7.4.1 Defining our Auction.Item schema
A database is made up of tables that store information in rows. Each row has
information that corresponds to columns that each table defines. For example, if we
needed to store information about a menu for a coffee shop, there could be a table
named "menu_items" that stores that information. That table would define the kind
of information we need to store. They could be something like Table 6.2.

Table 7.2. A theoretical table storing coffee shop menu items

Column name Data type Example


title String Fancy Espresso
description String A little pick-me-up
price Integer 295 [a]
[a] Why store the price as an integer instead of a Float (like 2.95)? Well, computers are notorious for
rounding and precision errors, so we eliminate those by just multiplying our price by 100 and storing it as an
integer.

If you open up auction_umbrella/apps/auction/lib/auction/item.ex, you’ll see


something somewhat similar that we have already defined—a defstruct defining
how our data looks for a Auction.Item. This was fine for our fake repo, but we
need to let Ecto know the details of how our data is structured. In order to do that,

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
140

we’ll delete the defstruct definition and instead use Ecto’s Ecto.Schema.schema/2
function. Ecto.Schema.schema/2 takes as arguments the table name the data will
live in, plus a list of field definitions (these will roughly match up with the columns
in our table) using Ecto.Schema.field/2. It will have a familiar feel, but we will
provide Ecto more information about our module’s data structure such as data type
and which table it can find all our information in. Listing 7.6 shows our
Auction.Item schema defined for Ecto.

Listing 7.6. Defining `Auction.Item’s schema for Ecto

defmodule Auction.Item do
use Ecto.Schema

schema "items" do
field :title, :string
field :description, :string
field :ends_at, :utc_datetime
timestamps()
end
end

A few notes on our schema:


1. use ing Ecto.Schema allows us to type just the function name provided by the
module (i.e. schema and field). Otherwise, we’d have to
type Ecto.Schema.schema and Ecto.Schema.field. It also provides other
functions under the hood to allow Ecto to what it needs to do.
2. Ecto.Schema provides a pretty extensive list of types for your data (and even
allows you to create custom ones!). Check the sidebar for a list of possibilities.
3. timestamps() is a simple way to let Ecto know that your data will
have inserted_at and updated_at columns with the timestamps of when the
particular row was created and updated, respectively
4. The keen-eyed among you may have noticed that we are not defining a field :id.
Ecto realizes that the majority of the tables you create will have a
corresponding id column and provides it by default. You can override that default
if you’d like, but we want the id column in this case.

Table 7.3 Some Often-Used Ecto Data Types

Ecto type Elixir type Example(s)


:id Integer 1, 100, 1_000
:integer Integer 1, 2, 3
:float Float 3.14, 9.3976387565388
:boolean Boolean true, false
:string UTF-8 string "Phoenix in Action"
:date Date 2018-10-30
:time Time 03:08:32.936199

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
141

:naive_datetime NaiveDateTime Date and time without timezone information


:utc_datetime DateTime Date and time with timezone information

7.4.2 Migrating our database


Once we have our schema defined, Ecto now knows how to interact with the
database when dealing with Items. But the database itself doesn’t know anything
about Items. We have created the database itself so far, but we haven’t created the
table or columns that our Auction.Item schema is referencing. That is our next
step—create the table and columns in our database.
To do that, we can use another Ecto construct known as a migration. Migrations are
pieces of code that allow you to build up and tear down your database
programmatically. This allows you to commit your migrations into a version
control system, share it with co-authors, and recreate the database structure as
needed, when needed. It also provides a good line separating code and database,
allowing Ecto to do the hard work of interacting directly with the database.
We can use a mix task that Ecto provides to easily create our migrations. mix
ecto.gen.migration will create the file (and any necessary directories) for a
migration that is timestamped in order to maintain the order of migrations. Not
only that, but like mix new, it will generate a small amount of boilerplate code that
will help you get started on your migration. In order to use it, you simply type mix
ecto.gen.migration along with the filename you’d like to use for your migration.
It is typically a good idea to be descriptive about what you are doing to the
database in your migration’s file name so you can easily find it later if required.
Let’s name our migration create_items since we are creating the items table.
Listing 7.7 shows what the output was when I ran the command on my
development machine.

Listing 7.7. Creating our first migration

> mix ecto.gen.migration create_items


* creating priv/repo/migrations
* creating priv/repo/migrations/20180120041610_create_items.exs

If you peek into the file that was created


(priv/repo/migrations/20180120041610_create_items.exs for me; yours will be
different depending on when you ran the command), you will find that boilerplate
code that was generated for you. Listing 7.8 shows that boilerplate.

Listing 7.8. Boilerplate migration code

defmodule Auction.Repo.Migrations.CreateItems do
use Ecto.Migration

def change do

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
142

end
end

An Ecto.Migration is made up of a single change/0 function, or an up/0 function


accompanied by a down/0 function. These tell Ecto how you’d like to change your
database in this particular migration. If you provide both and up/0 and
a down/0 function, Ecto will run the code in up/0 as it is building your database
migration by migration and it will run down/0 as it is tearing your database down. If
you only provide a change/0 function, Ecto will be smart enough to know how the
database changes as it goes up and down. Typically, it is plenty of information to
only give Ecto a change/0 migration but there are times where you might need
more control over how specific tables are torn down (such as removing specific
relevant data or notifying some external service). up/0 and down/0 are for those
times.
In our case, creating a table is simple enough that we will stick with the
provided change/0 function. Ecto provides a number of functions to define our
table’s structure. For this situation, when we want to create a table, we will use
the create/1 function to create a table. create can create tables, indices, and
constraints, but we want to create a table in this case. So the argument we will
provide create/1 is the fact that we want to create a table, provide it’s name, and
then provide a list of actions (via functions) to take on the table after creating it (in
our situation, adding columns).
Each column is added by using the add/3 function which accepts the name of the
column (provided as an Atom), what type of data it will contain, and any options
you’d like to specify (such as default values). add/3 will look a lot like
the field function we used when defining the schema for Auction.Item. Also, just
like in our schema, we do not have to specify that we want an :idcolumn (it creates
one by default), and we can use the timestamps() function to automatically
generate inserted_at and updated_at columns.
Listing 7.9 shows how we’d like the create our table in our migration.

Listing 7.9. Filling out the data for our table creation migration

defmodule Auction.Repo.Migrations.CreateItems do
use Ecto.Migration

def change do
create table("items") do
add :title, :string
add :description, :string
add :ends_at, :utc_datetime
timestamps()
end
end

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
143

end

Now that we have our migration filled out that describes to Ecto exactly what we’d
like to do in our migration, we can then use a Mix task to ask Ecto to actually run
the migration. Ecto provides a Mix task that lists the application’s migrations and
their current status (whether they are "up" or "down"). If you run mix
ecto.migrations (like in Listing 7.10), you will see that list.

Listing 7.10. Running mix ecto.migrations

> mix ecto.migrations

Repo: Auction.Repo

Status Migration ID Migration Name


--------------------------------------------------
down 20180120041610 create_items

We can see by the output that our new migration has not yet been run on the
database. mix ecto.migrate will migrate any migrations that haven’t yet been run.
Ours is the only one so far, so it will run it. When you run it, you will see some
output from Ecto describing exactly what it is doing to your database. This is the
output I saw when I ran the command.
> mix ecto.migrate
20:41:27.725 [info] == Running Auction.Repo.Migrations.CreateItems.change/0
forward
20:41:27.725 [info] create table items
20:41:27.809 [info] == Migrated in 0.0s

You just created a database table! Really easy and fast, huh? Beyond that, you
didn’t need to know a lick of SQL or the small intricate differences between how
one database does things vs another (like MySQL vs PostgreSQL). It just works.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
144

Figure 7.1. mix ecto.migrate vs mix ecto.rollback

What if we made a mistake and we weren’t quite ready to migrate yet? Ecto
provides a mix task for that as well. You can run mix ecto.rollback to roll back
just the last migration either using its down/0 function explicitly provided in the
migration file, or by reversing the changes it did in the change/0 function. We have
no data in our database, so we can try out the feature without destroying any data
we need.
> mix ecto.rollback
20:47:29.418 [info] == Running Auction.Repo.Migrations.CreateItems.change/0
backward
20:47:29.418 [info] drop table items
20:47:29.466 [info] == Migrated in 0.0s

We can see that Ecto is smart enough to know that while we created an items table
when we migrated forward (or up), the reverse is to drop (or destroy)
the items table when we migrate backwards (or down). While mix
ecto.rollback is extremely helpful, it can be dangerous as well. If we had
thousands of rows of customer data in that table, it would all be gone now! Use

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
145

with care.
Note that ecto.migrate attempts to bring as many migrations up as possible
while ecto.rollback only rolls back one migration at a time.
But to continue with our Auction application, we’ll need that table to exist.
Run mix ecto.migrate again to re-create the table before moving on.
7.4.3 Pointing our API to the new Repo
When we initially created our Auction application, we created alongside it a fake
repo to allow us to create our API without having to worry about a real database. It
is now time to point our API to use our new database. We made it really easy to do
that by not referencing the repo directly, but through a module context
variable. lib/auction.ex is the file that provides our API and does the work of
talking with our repo. The only thing we need to change in that file right now is
which repo to point at. It currently reads:
@repo Auction.FakeRepo

Change that line to now point to our real repo.


@repo Auction.Repo

7.4.4 Instructing the Application To Supervise the Database Connection


We have one final step before we can test out our new database connection. While
we have already defined our schema, created the table in the database containing
the columns we need, and pointed our API to the new repo, we still haven’t really
told our application to connect to the database.
The best way to do that is through a Supervisor. We haven’t discussed Supervisors
and Workers much yet in this book, but allowing a Supervisor to supervise a
Worker allows it to ensure that it is running. In this instance, our Worker will be
the connection to the database server. Supervising the connection will allow it to
attempt to reconnect to the database if the connection were ever severed (along
with other benefits whose discussion doesn’t fit here). Because of that, we need to
set up our first Worker to be supervised!
The place to set up Workers to be supervised is in the
auction_umbrella/apps/auction/lib/auction/application.ex file that was
automatically generated for us when we used mix new. Right now, it mostly
contains comments that help us figure out exactly how we can configure our
workers and supervisors. It can get a little overwhelming to think through all the
options and the great depth of functionality provided with Supervisors and Workers
doesn’t help that feeling get better.
Fortunately for us, Ecto has made it super easy. Do you remember how we put the
line use Ecto.Repo, otp_app: :auction in our lib/auction/repo.ex module?
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
146

That one line provided our module all the information it needed to become a
supervised Ecto worker. All we have to do is specify that we’d like to have it
supervised. To do so, add {Auction.Repo, []} to the children list in
lib/auction/application.ex. This provides our application with enough
information to know that we want that worker (in the list of workers) to be
supervised at startup. Right now it is the only worker, but we can add more to the
list as needed. Listing 7.11 is how your lib/auction/application.ex module
should look after adding our worker.

Listing 7.11. Adding our Repo the list of workers to be Supervised

defmodule Auction.Application dO
use Application

def start(_type, _args) do


# List all child processes to be supervised
children = [
# Starts a worker by calling: Auction.Worker.start_link(arg)
# {Auction.Worker, arg},
{Auction.Repo, []}
]

opts = [strategy: :one_for_one, name: Auction.Supervisor]


Supervisor.start_link(children, opts)
end
end

7.4.5 Did it work? Let’s test it out!


Finally, the exciting part—we get to test out if our database connection is running
and we have set everything up correctly. Since we set up our database connection
to start automatically with our application in listing 6.11, all we need to do is start
it up! As in the past, we will interact with our application through an IEx session
for now (iex -S mix).
Once we are in IEx, we can utilize our API calls to interact with the database. In
order to list all the items we currently have (which is none), we can
run Auction.list_items, just like we did when we had our fake repo running. For
us right now though, we will just get an empty list (as in Listing 7.12) since we
haven’t actually added any rows to our database (soon!). So why run the query?
Well, it will not only ensure that the database connection is up and running, but
also that Ecto is talking to it correctly and without error.

Listing all the Items in our database (none)

iex(1)> Auction.list_items()

21:16:18.226 [debug] QUERY OK source="items" db=1.5ms

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
147

SELECT i0."id", i0."title", i0."description", i0."ends_at" FROM "items" AS i0 []


[]

If you see something similar to the above, congratulations! Our application is


talking to our real database via Ecto! Ecto provides some debug output to show you
exactly how it is going about interacting with our database. In this case, you can
also see the exact SQL statement it generated for the PostgreSQL database in order
to list the items (SELECT i0."id", i0."title", i0."description", i0."ends_at"
FROM "items" AS i0 []). Finally, you can see the return of the function call ([])
that shows us we have no items yet.
Also try running Auction.get_item/1 and Auction.get_item_by/1. One will give
you an error, and one will return nil. Which do you think does what and why? We
will fix both instances soon but try experimenting a little with each of the three API
calls we have currently created in Auction and examine Ecto’s debug output.
You’ll soon get a good grasp on what it is trying to do.

7.5 Creating, Retrieving, and Deleting Data From the Database


We now have a working database connection and the beginnings of an API. If you
were wondering how the API we built just works so easily even after we moved
from a fake, static repo to a live database, it is because we wrote functions for our
fake repo that mirrored functions that Ecto provides. The sidebar and Tables 3 and
4 shows a truncated list of functions that Ecto.Repoprovides (and gives
our Auction.Repo through the use Ecto.Repo call at the top of our module). There
are a big handful more functions available, but these are the ones you will likely
use the most.

Some of Ecto.Repo’s database functions


Ecto provides a number of functions through Ecto.Repo to interact with your database.
Some of the more often-used ones are below, but you can always check out the full
documentation to find them all along with some great example usage. 28

Table 7.4. Data retrieval

Function Description Returns


all/2 Retrieves every row in the database that a List
matches the passed query
get_by/3 Retrieves a single row from the database that the row (if found) or nil if not found
matches the passed query
get/3 Retrieves a single row referenced by the the row (if found) or nil if not found
given primary key
one/2 Retrieves a single row that matches the the row (if found) or nil if not found; if more
passed query than one row is found, an error is raised

28
hexdocs.pm/ecto/Ecto.Repo.html
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
148

get_by/3 and get/3 have sister functions that end with a bang (e.g. get!/3). Those
versions of the functions raise an error if a row cannot be found based on the passed query
(instead of just returning nil).

Table 7.5. Data modification

Function Description Returns


delete/2 Deletes a row referenced by the given primary key {:ok, row}
insert/2 Inserts a row into the database based on the given struct {:ok, row} or {:error,
changeset}
update/2 Updates a row with the data in the given struct {:ok, row} or {:error,
referenced by the given primary key changeset}

The above three functions have sister functions that end with a bang (e.g. insert!/2) that
returns the struct/row directly (instead of in a tuple with :ok) if found or raises an error if not
found (instead of returning a tuple beginning with :error).
Each of the bang and non-bang versions have their uses depending on how you want your
application to react to data not found in the database.

7.5.1 Inserting data


The first thing we’ll want to do with our new database setup is insert some data to
play with. To do that, use insert/2 or insert!/2. Since we typically want to keep
our API separate from our database calls, we will first create an API call to insert
an Item into the database in lib/auction.ex. Ecto.Repo.insert/2 knows what table
to insert the data into based on the struct that we give it. The only struct we
currently have (Auction.Item) knows where it goes because of how we defined
its schema. Can you start to see how the pieces are fitting together?
In order to make inserting Item data more explicit but also a little easier at the same
time, we can design our API so that we only have to pass a map (%{}) instead of a
full struct (%Auction.Item{}). Elixir provides a function named Kernel.struct/2
that changes a Map to a struct based on the arguments provided. We’ll use that
function to change a Map and its data to the Auction.Item struct and then pass that
struct into the Ecto.Repo.insert/2 function. Listing 7.13 shows our new function
in the lib/auction.ex module.

Listing 7.13. Adding insert_item/1 to Auction

def insert_item(attrs) do
Auction.Item
|> struct(attrs)
|> @repo.insert()
end

Since we are using the insert/2 function instead of the bang version (insert!/2),
©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
149

we can expect to get either an {:ok, struct} or {:error, changeset} as a return


value. We will go into what exactly a changeset is in depth in chapter 7, so don’t
worry about them for now. But we do want to worry about whether we are getting
an :ok or an :error as the first value returned. We can use pattern matching to
ensure the query took place as we intended. Save lib/auction.ex with our new
API function and let’s use it to insert our first Item into the real database. We will
pattern match the return value with {:ok, item} to ensure there were no errors.
You can attempt to do so on your own in an IEx session, or follow along with
Listing 7.14.

Listing 7.14. Inserting our first Item

iex(1)> {:ok, item} =


iex...> Auction.insert_item(
iex...> %{title: "Wargames BluRay",
iex...> description: "Computer games and thermonuclear war",
iex...> ends_at: ~N[2018-02-22 11:43:39]}
iex...> )

08:43:10.661 [debug] QUERY OK db=3.3ms


INSERT INTO "items" ("description","ends_at","title","inserted_at","updated_at")
VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["Computer games and thermonuclear war",
{{2018, 2, 22}, {11, 43, 39, 0}}, "Wargames BluRay", {{2018, 1, 20}, {16, 43, 10,
657375}}, {{2018, 1, 20}, {16, 43, 10, 657389}}]

{:ok,
%Auction.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">,
description: "Computer games and thermonuclear war",
ends_at: ~N[2018-02-22 11:43:39], id: 1,
inserted_at: ~N[2018-01-20 16:43:10.657375], title: "Wargames BluRay",
updated_at: ~N[2018-01-20 16:43:10.657389]}}

iex(2)> item
%Auction.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">,
description: "Computer games and thermonuclear war",
ends_at: ~N[2018-02-22 11:43:39], id: 1,
inserted_at: ~N[2018-01-20 16:43:10.657375], title: "Wargames BluRay",
updated_at: ~N[2018-01-20 16:43:10.657389]}

Listing 7.14 shows that Ecto provides debug output describing exactly what it is
doing with the database including the SQL it generated and submitted to the
database. It also shows the complete return value of {:ok, …} which we pattern
matched against with {:ok, item}. We now have the database version of the data
in the item variable which we can then use how we’d please.
7.5.2 Retrieving data
We already went over retrieving data in this chapter, but now that we have actual
data to retrieve, we can have a quick review. We have created three functions in

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
150

our API that allow us to retrieve items: list_items/0, get_item/1, and


get_item_by/1. Since we now have an item in our database with the id of 1 and
title of Wargames BluRay, we can utilize those functions to practice retrieving
data as in Listing 7.15. And guess what? Since we initially created our API to
match Ecto’s, no further changes are required in the Auction module!

Listing 7.15. Retrieving data in different ways

iex(3)> Auction.list_items

09:45:33.007 [debug] QUERY OK source="items" db=2.0ms


SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at",
i0."updated_at" FROM "items" AS i0 []
[%Auction.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">,
description: "Computer games and thermonuclear war",
ends_at: #DateTime<2018-02-22 11:43:39.000000Z>, id: 1,
inserted_at: ~N[2018-01-20 16:43:10.657375], title: "Wargames BluRay",
updated_at: ~N[2018-01-20 16:43:10.657389]}]

iex(4)> Auction.get_item(1)

09:45:57.537 [debug] QUERY OK source="items" db=1.9ms


SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at",
i0."updated_at" FROM "items" AS i0 WHERE (i0."id" = $1) [1]
%Auction.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">,
description: "Computer games and thermonuclear war",
ends_at: #DateTime<2018-02-22 11:43:39.000000Z>, id: 1,
inserted_at: ~N[2018-01-20 16:43:10.657375], title: "Wargames BluRay",
updated_at: ~N[2018-01-20 16:43:10.657389]}

iex(5)> Auction.get_item_by(%{title: "Wargames BluRay"})

09:46:53.205 [debug] QUERY OK source="items" db=2.5ms


SELECT i0."id", i0."title", i0."description", i0."ends_at", i0."inserted_at",
i0."updated_at" FROM "items" AS i0 WHERE (i0."title" = $1) ["Wargames BluRay"]
%Auction.Item{__meta__: #Ecto.Schema.Metadata<:loaded, "items">,
description: "Computer games and thermonuclear war",
ends_at: #DateTime<2018-02-22 11:43:39.000000Z>, id: 1,
inserted_at: ~N[2018-01-20 16:43:10.657375], title: "Wargames BluRay",
updated_at: ~N[2018-01-20 16:43:10.657389]}

7.5.3 Deleting data


Of course, there may come a time when we no longer need specific rows in the
database—we’ll need a way to delete data. Ecto.Repo provides the delete/2
and delete!/2 functions for that purpose. It is a pretty simple function that takes
a struct as its argument and deletes the row that matches that struct’s id.
By this point, you probably know the drill: we want to keep database and API
separate, so let’s create our own border in our Auction module instead of

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
151

calling Auction.Repo.delete/2 directly. Since Ecto’s function is so simple, our


border function will also be very simple—just passing the struct through to Ecto.
Listing 7.16 shows the function definition that should be added to lib/auction.ex.
In it, we use pattern matching on the argument to ensure that what is passed into
our function is in fact an Auction.Item struct before we pass it on through to our
repo. That way, it’ll throw an error if we try to pass something other than
an Auction.Item struct in to the function.

Listing 7.16. Adding delete_item/1 to Auction

def delete_item(%Auction.Item{} = item), do: @repo.delete(item)

7.5.4 Updating data


We’ve inserted, retrieved, and deleted data from our database. Now what about
updating? In order to update data with Ecto, we need something called a
Changeset. At first glance, it can seem limiting that Ecto requires a Changeset in
order to simply update a row in the database, but you’ll see that it is very powerful
and can save you a lot of heartache when used correctly. In fact, it is such a deep
and meaningful topic that the whole next chapter is devoted to Changesets and
updating/verifying data as it goes into our database.
With that in mind, we’ll wrap this chapter up. Before you move on, I encourage
you to create, retrieve, and delete more Item s from your database. Doing so will
get you used to interacting with your database and the API that we have created,
plus provide more data for us to eventually work with.
7.5.5 What about the web site?
One more thing before you go: you know how I’ve been harping on keeping the
database concerns and business logic apart from the web site concerns? You are
about to see one of the benefits of doing that. Navigate to
auction_umbrella/apps/auction_web and run mix phx.server. Load up
0.0.0.0:4000 in your browser. What do you see? Our auction site is now
displaying data directly from our database instead of the fake repo (see Figure 2)!
We didn’t have to change a single line of code in the web side of the umbrella app
because we kept the API of our business logic exactly the same.

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action
Licensed to Rodrigo Dominguez <[email protected]>
152

Figure 7.2. The web side of our application didn’t require any changes to see real database
data

7.6 Summary
In this chapter you learned
• Ecto provides a number of Mix tasks to make interacting with your database setup
simple
• Use Ecto’s Ecto.Schema.schema/2 function to let Ecto know how your data is
structured in the database
• Use Ecto’s Ecto.Migration module and Mix task to create and run migrations that
change the structure of your database programmatically
• Ecto provides functions for inserting, retrieving, and deleting data from the
database, though it is a good idea to write your own functions that utilize Ecto’s to
provide a clean border between concerns

©Manning Publications Co. We welcome reader comments about anything in the manuscript - other than typos and
other simple mistakes. These will be cleaned up during production of the book by copyeditors and proofreaders.
https://forums.manning.com/forums/phoenix-in-action

You might also like