31,19 €
Learn to build a high-performance functional prototype of a voting web application from scratch using Elixir and Phoenix
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.
This book is for people with a basic knowledge of Elixir, who want to start building web applications. Prior experience with web technologies is assumed.
Brandon Richey is a software engineer and Elixir enthusiast who has written a large number of popular Elixir tutorials. He has been doing professional and hobby programming projects spanning topics from healthcare, personal sites, recruiting, and game development for nearly 20 years! When not programming, Brandon enjoys spending time with his family, playing (and making) video games and working on his drawings and paintings!Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 479
Veröffentlichungsjahr: 2018
Copyright © 2018 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Kunal ChaudhariAcquisition Editor: Larissa PintoContent Development Editor: Mohammed Yusuf ImaratwaleTechnical Editor: Ralph RosarioCopy Editor: Safis EditingProject Coordinator: Hardik BhindeProofreader: Safis EditingIndexer: Priyanka DhadkeGraphics: Jason MonteiroProduction Coordinator: Shantanu Zagade
First published: April 2018
Production reference: 1250418
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78728-419-7
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Brandon Richey is a software engineer and Elixir enthusiast who has written a large number of popular Elixir tutorials. He has been doing professional and hobby programming projects spanning topics from healthcare, personal sites, recruiting, and game development for nearly 20 years! When not programming, Brandon enjoys spending time with his family, playing (and making) video games and working on his drawings and paintings!
Atul S. Khot is a self-taught programmer and learned from reading C and C++ code. A Linux aficionado and a command-line guy at heart, Atul has dabbled in multiple languages. He is deeply interested in functional languages and massively parallel software systems. Atul speaks at software conferences, and he is a past Dr. Dobb's Jolt award judge. He was the author of Learning functional Data Structures & Algorithms and Scala Functional Programming Patterns, both published by Packt Publishing.
LarryRohrs worked for a large financial firm as an IT professional for 25 years. Professional coding projects were focused on infrastructure in APL-derivative languages, C, and C++. As a senior manager, Larry managed a large, global, IT team responsible for collecting, verifying, organizing, and expanding key reference data available through large, distributed databases. He is currently retired and enjoys spending more time with family and hobbies.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Phoenix Web Development
Packt Upsell
Why subscribe?
PacktPub.com
Contributors
About the author
About the reviewers
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
A Brief Introduction to Elixir and Phoenix
Introducing IEx and Elixir
What is IEx?
Variables in Elixir
Immutability in Elixir
Understanding the different types in Elixir
Getting more information with the i helper
Getting more information with the h helper
Using IEx and helpers to understand types
Your objects have no power here
Introduction to Phoenix
Installing Phoenix 1.3
Creating a new Phoenix project
Running the Phoenix Mix Task
Running the Phoenix server for the first time
Phoenix's default application structure
Configuration files
Assets files
Private files
Tests
Other directories
The most important directory: lib
A note about how data flows in Phoenix
Summary
Building Controllers, Views, and Templates
Understanding the flow of Phoenix connections
Creating our Social Voting project
Creating a poll controller
Understanding the controller's structure
Building the poll controller
Understanding templates
Passing data to our templates
Writing controller tests
Understanding the code behind tests
Writing the poll controller test
Summary
Storing and Retrieving Vote Data with Ecto Pages
Understanding the role of schemas
Creating a new migration
Creating the Polls table migration
Creating our Options table migration
Creating our Poll schema
Testing our Poll schema
Creating our Option schema
Understanding the gotchas of associations
Understanding the role of contexts
Creating a Votes context
Grabbing a list of data
Understanding Ecto query writing
Hooking up the context to our controller
Creating a new poll
Creating the new action in the controller
Creating our create function
Writing our unit tests
Summary
Introducing User Accounts and Sessions
Adding user accounts
Designing our user schema
Creating our user schema
Creating our accounts context
Writing our user unit tests
Creating a user signup page
Creating the routes
Creating the controller code (with tests)
Setting up the password functionality
Installing Comeonin
Adding Comeonin to the user schema file
Updating our tests
Updating the UI to include password fields
Creating a user login page
Building our create session function
Writing session controller tests
Summary
Validations, Errors, and Tying Loose Ends
Connecting polls to users
Creating the migration
Modifying the schemas
Fixing broken poll tests
Sending a user ID through the controller
Retrieving data from sessions
Writing our Poll Controller's tests
Restricting access via sessions
Working with validations and errors
Making usernames unique
Writing custom validations
Displaying validation errors in our forms
Summary
Live Voting with Phoenix
Building channels and topics in Phoenix
Understanding sockets
Understanding channels
Working with ES2015 syntax
Imports and exports
let and const
Fat-arrow functions
Variable and argument destructuring
Sending and receiving messages with channels
Conditionally loading our socket
Sending messages on the socket
Allowing users to vote on polls
Making voting real-time
Building our dummy functionality
Changing our dummy code to push to the server
Writing our server channel code for live voting
Refactoring our channels away from the index
Moving the channel functionality to show
Starting our channel tests
Summary
Improving Our Application and Adding Features
Designing and implementing our new features
Implementing file uploads in Phoenix
Working with uploads in Phoenix
Adding file uploads to our new poll UI
Hooking up the uploads to our database
Writing the migration file
Modifying the schema and the context code
Completing the votes context for the image uploads
Implementing voting restrictions
Creating the vote record migration
Creating the vote record schema
Hooking up restrictions
Fixing the broken tests
Summary
Adding Chat to Your Phoenix Application
Adding chat to a Phoenix application
Working with the chat schema
Building the chat schema
Designing our message functionality
Implementing message functions in our context
Writing our unit tests
Fixing navigation in our application
Creating the chat UI
Building the UI Itself
Creating our chat channel
Sending chat messages
Hooking up the new JavaScript code to Phoenix
Refactoring for poll chats
Fixing up our tests
Returning to a passing test suite
Summary
Using Presence and ETS in Phoenix
Utilizing Presence and ETS to make our app more robust
What is Presence?
Updating our chat UI
Elixir implementation
JavaScript implementation
Using ETS
Why use ETS?
Experimenting with ETS in an IEx window
Creating our Presence ETS table and GenServer
Setting up the GenServer
Creating the public interface for the GenServer
Implementing the cast and call logic
Hooking up the GenServer to our application
Storing Presence data in ETS
Retrieving Presence data in ETS
Summary
Working with Elixir's Concurrency Model
Introduction to Elixir's concurrency model
The difference between concurrency and parallelism
In process 1
Run process 1
In process 1
In process 2
Run process 1 and process 2 at the same time
Talking about OTP/understanding the model
Working with an example
Diving deeper into the concurrency model
The model - what is a process?
The model - what if our process crashes?
The model - what is a task?
The model - what is an agent?
The model - what is a supervisor?
The model - what is an application?
Using GenServers
Summary
Implementing OAuth in Our Application
Solidifying the new user experience
Shoring up our tests
Building a good development seeds file
Hooking up our polls index
Adding Ueberauth support
Adding OAuth login support for Twitter with Ueberauth
Setting up our application with Twitter
Configuring the Twitter login process in Phoenix
Modifying the users schema
Implementing the Twitter login in Phoenix
Adding OAuth login support for Google with Ueberauth
Configuring Google to allow OAuth
Configuring Ueberauth in Google
Implementing Google OAuth for Ueberauth and Phoenix
Summary
Building an API and Deploying
Building our API
Building an API in Code
Expanding Our API Request
Authenticating Against our API
Allowing a user to navigate to their profile page
Introducing API keys to the database
Validating API Keys
Dealing with Error Handling in APIs
Implementing an API Resource Show
Adding an Error Handler for 404s for JSON
Deploying Phoenix applications to production
Initial requirements for deployment into production
Alternative Deployment Strategies
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
With Elixir and Phoenix, you build your application the right way the first way: ready to scale and ready for the increasing demands of real-time web applications.
This book will cover the bare basics of the Phoenix web framework through building a community voting application and, in the course, discuss the new structure changes introduced in Phoenix v1.3. We'll cover the initial challenges of getting started with our app, working with the generators to learn more about the structure of a standard Phoenix app. From there, we'll build our application and work with Channels, Schemas, Contexts, and even dive into more advanced topics such as working with Tasks/Async and GenServers. By the end of this book, we'll have a strong grasp of all the core fundamentals of the Phoenix framework, and we'll have built a full production-ready web application from nothing!
This is for people who have started messing around with Elixir and have enjoyed what they've seen! We'll take those skills and apply them to building a full web application. If you have some knowledge of Elixir and have experience with other web frameworks in other languages and want to see what it's like to build a web application where concurrency and performance are first-class citizens, you're in the right place!
Chapter 1, A Brief Introduction to Elixir and Phoenix, goes over the basics of developing in Elixir and Phoenix and makes the readers understand some of the basic constructs available.
Chapter 2, Building Controllers, Views, and Templates, covers working with the fundamentals of every Phoenix application.
Chapter 3, Storing and Retrieving Vote Data with Ecto Pages, discusses working with data in our database.
Chapter 4, Introducing User Accounts and Sessions, begins to introduce the concept of Users into our system and introduces working with login, logout, and session management.
Chapter 5, Validations, Errors, and Tying Loose Ends, explores working on tightening up our application through validation, error-handling, and general tweaks.
Chapter 6, Live Voting with Phoenix, starts building out a real-time application with Phoenix and JavaScript.
Chapter 7, Improving Our Application and Adding Features, continues to build upon the solid foundation of our application and brings it closer to production-ready.
Chapter 8, Adding Chat to Your Phoenix Application, adds even more real-time feature support.
Chapter 9, Using Presence and ETS in Phoenix, teaches readers to use Phoenix's new Presence support to keep track of what users are logged in or logged out of our system.
Chapter 10, Working with Elixir's Concurrency Model, takes readers through how Elixir handles concurrency implementations at a deeper level.
Chapter 11, Implementing OAuth in Our Application, implements a new way for users to sign in with providers such as Twitter and Google.
Chapter 12, Building an API and Deploying, outlines finishing reading our application, adding an API to interact with our application, and finally finishing deploying our application to production.
Readers should already have at least a basic understanding of the Elixir programming language and some beginner-level knowledge of common web development terms and techniques
You will also need an internet-capable programming environment where you can install required software such as Elixir, Phoenix, Node.js, and Postgres
You can download the example code files for this book from your account at www.packtpub.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packtpub.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub athttps://github.com/PacktPublishing/Phoenix-Web-Development. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available athttps://github.com/PacktPublishing/. Check them out!
Feedback from our readers is always welcome.
General feedback: Email [email protected] and mention the book title in the subject of your message. If you have questions about any aspect of this book, please email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packtpub.com.
In this book, we'll walk through the process of building a functional prototype of a social web application that will rely on real-time data updates. If you've ever used any sort of live voting application out there (such as Straw Poll or Twitter Polls), then you're probably pretty comfortable with the idea already. If not, I'll summarize our application so that you know what you're going to be building throughout this book.
Our application will allow users to register for new accounts on our site. From there, they will have the option to create new polls for other users (either while logged in or anonymously) to vote on. We want to make sure that the votes for the polls are recorded and broadcast out to anyone watching the polls in real-time, so we'll take advantage of Phoenix's built-in channel support to provide this.
In addition, our application will allow users to create chat rooms that will be displayed alongside the poll. After they've voted, users will be allowed to chat and discuss the results live as the votes come in. Users will also be allowed to post images, which will be processed, and uploaded to S3.
Users who create polls will be able to decide who is allowed to vote on their polls; for example, either only logged-in users or any user. Users will be able to modify their polls until they go live.
Users who own the polls should be able to participate in real-time discussions with the people voting on and viewing their polls, including anonymous users. Being able to communicate with each other takes advantage of some of the more advanced real-time concepts that are powering Elixir behind-the-scenes and running separately from the main web portion of our Phoenix application. These concepts demonstrate how we can build larger and more performance-intensive applications!
Now, before we really dive into developing this application, we'll need to make sure we understand some of the tools that are going to help us build this application. The assumption is that you're coming into this with an existing understanding of Elixir, but if not, we will briefly cover some core Elixir concepts while also learning about a tool that will be critical for building a great application in Elixir: the IEx shell and the debugger!
To recap, in this chapter we will cover the following topics:
Basic Elixir concepts
The interactive Elixir shell, IEx
Installing Phoenix
Creating a new Phoenix project with Mix tasks
An introduction to the Phoenix project structure
We'll start off by talking a little bit about the Elixir programming language that Phoenix sits atop. The most important thing to note, especially if you're coming from another programming language such as Ruby, Go, PHP, JavaScript, or Java, is that there is one significant difference between Elixir and the rest: Elixir is a functional language. While this doesn't change everything dramatically, it does introduce a few gotchas that we will need to get out of the way.
Before we dive too far into those gotchas, let's first get acquainted with a tool that is going to make our development process in Elixir much simpler: IEx.
The good news: Elixir includes a tool called a Read-Evaluate-Print-Loop (REPL), which is essentially an Elixir shell. You can think of this as being similar to an irb in Ruby or the node shell in Node.js. It is a very detailed and helpful tool that we'll be referring to quite a bit in our journey of building this full web app! To open REPL up (assuming you have Elixir installed), run the following command:
$> iex
You should see something similar to the following snippet appear on your screen:
$> iex
Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:4:4] [ds:4:4: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)>
Now we can start messing around with some sample Elixir code! Let's start off with a couple of base scenarios.
Elixir has a number of different built-in types that we'll be working within the course of building our applications. They are the following:
Strings (sometimes referred to as binaries)
Integers
Floats
Lists
Maps
Keyword lists
Tuples
Modules
Functions (functions themselves break into two separate types: module functions and anonymous functions)
Let's take a look at the various representations of these types and use some of the tools in IEx to understand more about what we're working with.
IEx also provides us with another incredibly helpful built-in function: h. Similar to i, h has two arities available for us to use: h/0, which displays the help page for IEx, and h/1, which displays the help for a particular module. So, while the following example won't work:
iex(5)> h 5
Invalid arguments for h helper: 5
This following example will:
iex(6)> h Integer
Integer
Functions for working with integers.
Using i and h effectively will go a long way towards helping us understand more of Elixir as we go along!
Phoenix is a web framework that sits on top of the Elixir programming language, much in the same way that Rails sits atop Ruby or Express sits atop Node and JavaScript. There are a few areas where Phoenix shares a lot of the same core ideas and beliefs of other frameworks and areas where Phoenix differs pretty heavily.
Phoenix is very much designed to be a standard Elixir application and thus abides by the same rules and the same principles, but also encompasses all of the same things that make Elixir so great to work with! In my mind, the first and biggest thing that Phoenix gets via Elixir is first-class and dead-simple concurrency support. Writing code that performs and scales well on multiple core machines (that is, basically every single computer out there nowadays) is a breeze, and when you're just starting out building your Phoenix application, you won’t even have to think about it. It isn't until you start diving more heavily into the more advanced topics, such as OTP, GenServers, and Async Tasks, where you really need to start thinking deeply about your concurrency models and how everything fits together.
Phoenix also benefits very heavily from being based on a functional immutable language. Large codebases remain very simple to reason with, and the fear of introducing significant breaking changes because of a mutation deeply-nested in your code is now a thing of the past! If you're coming from a language where you've built a complex application and a simple change ends up breaking everything, this should be a breath of fresh air to you. I referenced this in one of my earlier examples, but when you actually see it in action and understand why it works the way it does, trust me, you won't want to go back to the old ways of building applications!
Before we do anything else, let's talk briefly about how to actually install Phoenix so that you can get started on working with it as soon as possible. The best (and most up-to-date) instructions can be found on the Phoenix framework website (https://phoenixframework.org), but just in case, here you are. Please note that the following instructions assume you already have Elixir installed.
For best results, you'll want to make sure you have the most recent version of Hex installed on your local machine. Again, the assumption here is that you already have Elixir installed on your computer:
$ mix local.hex
Found existing entry: /Users/brandon.richey/.mix/archives/hex-0.16.1
Are you sure you want to replace it with "https://repo.hex.pm/installs/1.5.0/hex-0.17.1.ez"? [Yn] y
* creating /Users/brandon.richey/.mix/archives/hex-0.17.1
Now we'll move on to installing Phoenix itself. Installing Phoenix is a little bit different from just installing something via a hex package on an existing Elixir project. You'll want to use Phoenix’s project generators to get your project up and running, as there is a lot of additional setups required compared to a small, standard Elixir project. This is why you need to go through a separate process to install Phoenix.
To install the Phoenix framework and get access to the Mix tasks needed to create new Phoenix projects, you'll want to run the following code:
$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
* creating /Users/brandon.richey/.mix/archives/phx_new
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!
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:
First off, all of the standard Elixir dependencies that exist for all Phoenix applications will be downloaded from
hex
and compiled.
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.
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
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:
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
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!
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.
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).
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.
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).
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.
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.
We should now have a fine working knowledge of a standard Phoenix application. We should now understand how the application's structure, what the different pieces of the Phoenix application are, and how they're all used in conjunction to send something back to the browser when we, for example, send a request to http://localhost:4000/.
In the following chapters, we'll dive more into each of the functional areas of a Phoenix application and understand them at an even deeper level than this. Given that we have a strong foundation, we now need to move on to the real way to learn Phoenix: by building a new Phoenix application from start to finish!
This chapter is focused on the building blocks of any Phoenix application. By understanding what controllers, views, and templates are (and how they interact), it becomes much easier to build out our web application. We'll tackle this through the perspective of building the first major component of our Live Voting application, and by writing tests to cover the new functionality introduced.
The reader will become proficient in a lot of the basic tenets of using controllers, views, and templates. In addition, the reader will learn how the three pieces fit together via functional composition. Finally, they'll begin diving into writing their first tests covering controllers and views to start enforcing a strong and real-world systems development life cycle (SDLC). This will be from the perspective of building an actual application, so we'll start laying the framework for our voting app.
