Book Image

Phoenix Web Development

By : Brandon Richey
Book Image

Phoenix Web Development

By: Brandon Richey

Overview of this book

Phoenix is a modern web development framework that is used to build API’s and web applications. It is built on Elixir and runs on Erlang VM which makes it much faster than other options. With Elixir and Phoenix, you build your application the right way, ready to scale and ready for the increasing demands of real-time web applications. This book covers the basics of the Phoenix web framework, showing you how to build a community voting application, and is divided into three parts. In the first part, you will be introduced to Phoenix and Elixir and understand the core terminologies that are used to describe them. You will also learn to build controller pages, store and retrieve data, add users to your app pages and protect your database. In the second section you will be able to reinforce your knowledge of architecting real time applications in phoenix and not only debug these applications but also diagnose issues in them. In the third and final section you will have the complete understanding of deploying and running the phoenix application and should be comfortable to make your first application release By the end of this book, you'll have a strong grasp of all of the core fundamentals of the Phoenix framework, and will have built a full production-ready web application from scratch.
Table of Contents (14 chapters)
4
Introducing User Accounts and Sessions

Creating a new Phoenix project

Now that we have something in place to help us understand Elixir and Phoenix and we've installed everything necessary, we can start to discuss how to actually begin implementing our first project in Phoenix. To get started on a project and generate the Phoenix application skeleton we'll need to start developing, we'll run a special command using the installed Mix application that came with Elixir. We also added the Phoenix Hex archive to our local Hex installation, so we should have access to a few new Phoenix-specific Mix tasks, such as mix phx.new!

Running the Phoenix Mix Task

Phoenix has gone through a few iterations of general architecture and project structures, but as of version 1.3, they've stuck on a design that is incredibly elegant and easy to use. Instead of the sometimes clumsy system they previously had, where you had your models, your controllers, your views, and your templates and nothing in between, you can now design things around controllers, views, templates, contexts, and schemas. Before we start diving into what those differences are and why they’re so important, let's talk about the general project structure of a Phoenix application.

The first major thing is that Phoenix applications are considered first-class Elixir projects, so as such follow the same major rules. Generally, Elixir projects should have a test directory and a lib directory. Your test directory is where any new tests you write and any tests you run will live out of lib, on the other hand, is where the actual code for any actual work should go. Let's explore how these directories will get filled out by creating a small sample throwaway Phoenix application.

To create a new Phoenix application, we'll start off by running the mix task phx.new:

$ mix phx.new sampler
* creating sampler/config/config.exs
* creating sampler/config/dev.exs
* creating sampler/config/prod.exs
* creating sampler/config/prod.secret.exs
* creating sampler/config/test.exs
* creating sampler/lib/sampler/application.ex
* creating sampler/lib/sampler.ex
* creating sampler/lib/sampler_web/channels/user_socket.ex
* creating sampler/lib/sampler_web/views/error_helpers.ex
* creating sampler/lib/sampler_web/views/error_view.ex
* creating sampler/lib/sampler_web/endpoint.ex
* creating sampler/lib/sampler_web/router.ex
* creating sampler/lib/sampler_web.ex
* creating sampler/mix.exs
* creating sampler/README.md
* creating sampler/test/support/channel_case.ex
* creating sampler/test/support/conn_case.ex
* creating sampler/test/test_helper.exs
* creating sampler/test/sampler_web/views/error_view_test.exs
* creating sampler/lib/sampler_web/gettext.ex
* creating sampler/priv/gettext/en/LC_MESSAGES/errors.po
* creating sampler/priv/gettext/errors.pot
* creating sampler/lib/sampler/repo.ex
* creating sampler/priv/repo/seeds.exs
* creating sampler/test/support/data_case.ex
* creating sampler/lib/sampler_web/controllers/page_controller.ex
* creating sampler/lib/sampler_web/templates/layout/app.html.eex
* creating sampler/lib/sampler_web/templates/page/index.html.eex
* creating sampler/lib/sampler_web/views/layout_view.ex
* creating sampler/lib/sampler_web/views/page_view.ex
* creating sampler/test/sampler_web/controllers/page_controller_test.exs
* creating sampler/test/sampler_web/views/layout_view_test.exs
* creating sampler/test/sampler_web/views/page_view_test.exs
* creating sampler/.gitignore
* creating sampler/assets/brunch-config.js
* creating sampler/assets/css/app.css
* creating sampler/assets/css/phoenix.css
* creating sampler/assets/js/app.js
* creating sampler/assets/js/socket.js
* creating sampler/assets/package.json
* creating sampler/assets/static/robots.txt
* creating sampler/assets/static/images/phoenix.png
* creating sampler/assets/static/favicon.ico

Fetch and install dependencies? [Yn]

We'll now be asked if we want to fetch and install dependencies. If we say yes, a few things will happen:

  1. First off, all of the standard Elixir dependencies that exist for all Phoenix applications will be downloaded from hex and compiled.
  2. Next, all of the Node/JavaScript dependencies that Phoenix applications depend on (assuming you did not use the --no-brunch flag when you created your new Phoenix application) will be downloaded from npm and compiled.
  3. Assets will be built and set up appropriately via Brunch.

If we say yes, we should see something akin to the following output:

* running mix deps.get
* running mix deps.compile
* running cd assets npm instal node node_modules/brunch/bin/brunch build

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

$ cd sampler

Then configure your database in config/dev.exs and run:

$ mix ecto.create

Start your Phoenix app with:

$ mix phx.server

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

$ iex -S mix phx.server

When everything is done, we can enter our new project directory, create our database, and start up our Phoenix server!

$ cd sampler && mix ecto.create
Compiling 13 files (.ex)
Generated sampler app
The database for Sampler.Repo has been created
To create a database, you will need to have a username and password set up for your database server of choice that has the correct permissions or roles assigned that allow you to create databases. If you are working with a role or user that does not have that permission, you can also create the database manually and instead run mix ecto.reset.

Running the Phoenix server for the first time

There are two ways to start up the Phoenix server, and now that the application is set up and the database is there to support our application, we can move on to actually running it! The two different ways to run your application are either via Mix phx.server or in the IEx console. In the context of your application requiring debugging support via IEx, you need -S Mix phx.server. As a general rule, I only run my application in a local development environment through IEx. This allows you to get interactive debugging via IEx.pry, as well as the ability to perform things like Ecto queries or test calling public functions in modules.

Remember when we talked about the interactive help functions that are built-in to Elixir and can be accessed via IEx? Well, you can do the same thing with Phoenix functions, too! For example, let's say we want to know a little more information about how we send out JSON content directly from a controller, as shown in the following example:

iex(4)> h Phoenix.Controller.json

def json(conn, data)

Sends JSON response.

It uses the configured :format_encoders under the :phoenix application for
:json to pick up the encoder module.

## Examples

iex> json conn, %{id: 123}

Okay, so we now have our application and we have things up and running. If we visit our browser window, we should see the Phoenix startup page, as follows:

Phoenix's default application structure

As mentioned previously, Phoenix is itself a full-featured Elixir application, and as a result, tends to follow a lot of the same conventions and rules that other Elixir applications follow. We’ve briefly touched on the topic previously, but now it's time to get into it and take a look at how Phoenix projects are structured so that we can understand how to build on top of Phoenix. The starting directory structure looks a little something like the following:

├── README.md
├── assets
│ ├── brunch-config.js
│ ├── css
│ ├── js
│ ├── package.json
│ ├── static
│ └── vendor
├── config
│ ├── config.exs
│ ├── dev.exs
│ ├── prod.exs
│ ├── prod.secret.exs
│ └── test.exs
├── lib
│ ├── testapp
│ ├── testapp.ex
│ ├── testapp_web
│ └── testapp_web.ex
├── mix.exs
├── priv
│ ├── gettext
│ └── repo
└── test
├── support
├── test_helper.exs
└── testapp_web

Configuration files

First, we have a config directory in the root of our Phoenix application. This is where all of the application and web service configuration files will live. We typically have the config.exs, dev.exs, test.exs, prod.secret.exs, and prod.exs files by default with our Phoenix application. The first file, config.exs, is a file that stores generic configuration details that should be the same across all run-time environments for your application, whether they're testing, development, or production environments. The next few (dev.exs, test.exs, and prod.exs) are your environment-specific configuration files. Finally, we have our prod.secret.exs, which is auto-generated by Phoenix but not checked into source control by default. This file should never be checked into the source control for your application, as this is where sensitive information should live, such as API keys, secret keys, and database passwords. If this is ever checked into source control then it would be in the history of your application, which would be a pretty significant security concern for anyone having to maintain your Phoenix application!

Assets files

Next, we have our assets directory. This is where all of the front-end assets (images, CSS, JavaScript, and so on) live, as well as Brunch and NPM. (Your node_modules directory, for example, is found here.) The idea here is that by divorcing your front-end code and files from the rest of the work that Phoenix needs to do, Phoenix's developers can instead focus on making Phoenix great and leave the front-end and asset compilation problems to better solutions such as Brunch or Webpack, as well make asset compilation tool choices separately from those that created the framework. Even though Phoenix comes with Brunch by default, it's still straightforward to replace it with Webpack if that’s more suited to your speed.

Private files

There is also a priv directory, which is a little trickier to explain. Priv contains a lot of the helper and application setup code that is required. This contains your Repo's seeds file and migrations that need to be run (which we'll cover later), translations to your application via gettext, and finally, your static asset files (which have been built/compiled/transpiled/etc from your assets directory).

Tests

Your test directory contains all of the ExUnit tests for your application, which itself is broken up into two starting directories: (application name)_web and support (plus a test_helper Elixir script that contains some initialization code). (app)_web is used to contain the web application tests that cover controllers, contexts, views, templates, and so on, so you can think of this as the container for all of your Phoenix application tests. Support is instead used to bolster the functionality of your tests and make it easier to write new tests and share common logic or helpers. For the most part, we won't be modifying the code inside here very often. Most of the changes that we're going to make will instead be in the test/(app)_web directory and sub-directories.

Other directories

We also have a few miscellaneous directories that you won't really be interacting with at all. _build and deps, for example, contain various build artifacts and Elixir application dependencies (these won't actually get created until you build your application).

The most important directory: lib

Now we'll move on to the real meat of our Phoenix application: lib. Lib is where our application lives. By default, our Phoenix application is broken into two separate ideas. Using the application name of Sampler as an example, we will see two directories: lib/sampler and lib/sampler_web. The idea behind this is that every web application in Phoenix has at least two separate applications that work together to get the job done. The first is divorced from the idea of anything web-related, so there are no controllers or templates, JSON, or anything similar. One of the most common patterns that you’ll see here is all of your database-specific Ecto logic through contexts and schemas.

A context is a collection or boundary of domain-specific logic. For example, if you have users and organizations in your project, you may have a unifying context to those separate schemas called something like Accounts.

A Schema, on the other hand, is the one-to-one mapping of a database table to an application concept. Schemas need to be separated from the functionality of your code and used strictly to describe the shape of the data; this keeps your code pure from side-effects and helps make your code significantly easier to test in the long run.

Finally, we have lib/sampler_web. This is where all of the Phoenix-specific work gets done, so everything related to controller logic, templates, or views goes here in the appropriate sub-directory. Channel logic also falls underneath this particular design pattern. This is also where the endpoint.ex file lives, which defines how Plug constructs the Phoenix response to browser/API consumer/etc. It also determines how requests are parsed and how information is passed along to the Phoenix router.

Speaking of the router, our Phoenix router.ex file also lives here (again, because this is Phoenix-specific logic rather than the overarching common application functionality). This is where we will set up all of the rules to describe how to communicate between the browser and Phoenix's controllers.

A note about how data flows in Phoenix

If you're coming from the world of another web framework you might already be familiar with languages such as routers, controllers, templates, and views, but if you're not, let's talk a little bit about what those are, what they mean, and how the data flows in a Phoenix request all the way back out to the browser response. If you're already familiar with these topics, feel free to skip ahead to the next chapter.

When a request is received to a Phoenix application, the first thing that happens is that it gets handled by the endpoint. The endpoint's job is to take a look at the requests and to determine if there are any special functions or handlers that need to deal with the request. The request will flow through a series of plugs. A plug is a set of functionalities that takes in the connection data structure and performs a series of transformations and queries against the incoming request (for example, determining if the originator of the request is an approved server or making sure that the content types make sense). A plug must always take in a connection data structure (typically referred to as conn) and return out a conn, either modified or not. It can also additionally take in a set of options to determine how to modify the conn.

From there, the conn gets moved into the router via the endpoint. The router figures out where the information is coming from and where it is trying to get to. This is done via a combination of the URL hit, the content type, and so on. From here, if a valid route is found, the router will pass the conn on to the controller. A controller's job in a Phoenix application is to provide a means of determining what further transformations need to occur on the conn (which will eventually become our response from the server), as well as doing additional application logic such as running database queries, putting together templates, setting HTTP status codes, and much more. We can think of this as the glue for the different parts of our application that will help us construct our server's response.

The controllers then tell the view how to put together the data in the response and pass along the information it needs to determine the overall shape and feel of the response. It might be a JSON data structure if we're working with an API, or it may be a particular HTML template that we're sending back to the user with further information that is then sent along to the template. We can think of it as if the router answers where the controller answers what, and the view answers how. If we're not working with something simple, such as a JSON API, then there is an additional step that we have to work through called the template. The template helps Phoenix understand how, given a connection object, to build a response and what response to build, and a set of data to pass along to the consumer to build the logic that provides the nice look and feel we'd expect of a modern web app sending back HTML with layouts, partial pieces of content, and an overall structure.