Welcome! In this guide we'll go step by step to build an API with Elixir and the Phoenix Framework.
Note, i wrote this around 2017/18 so things might have changed. Also it's incomplete. Hopefully still useful. Yadayada.
Here's the plan:
- Install Elixir
- Create a new Phoenix project
- Connect a PostgreSQL database
- Deploy to Heroku
- Create CRUD endpoints for a model
- Configure the API to follow the JSON API specification
- Try out queries, sorting and filtering
(todo: create demo repo with nice commit history)
This is an overview of the most important projects we'll be using. If it looks scary, it's because it kinda is. The good thing is we don't have to go too deep as the Phoenix framework will lead the way.
Feel free to come back here, follow the links and read up on the documentation. It helps and is how I can write this now.
- Erlang is a functional programming language first released in 1986
- Elixir is another functional language on top of Erlang designed for building scalable and maintainable applications
- Mix is the build tool and CLI for Elixir that provides tasks for creating, compiling, and testing your application, managing its dependencies and more
- Hex is the package manager for the Erlang ecosystem (used via mix)
- IEx is Elixir's interactive shell
- Phoenix is an Elixir framework for building web applications
- Plug is "a specification and conveniences for composable modules between web applications". Middleware?
- Ecto is what you use to talk to the database
There's also Cowboy, the HTTP web server used by Phoenix and Poison, the JSON library.
Just to recap. Mix is the CLI build tool and Hex is the package manager. You generally don't interact with Hex directly. Instead it is used by mix
under the hood.
In Elixir, your projects dependencies are defined in a mix.exs
file. There is no equivalent to npm install
. To install a dependency, write its name and version directly in the file and run mix deps.get
.
Get help with mix help
or for a specific task ala mix help phx.new
.
- https://hexdocs.pm/mix/Mix.html
- https://hex.pm/docs/tasks
- https://hexdocs.pm/phoenix/phoenix_mix_tasks.html#content
We need to install Elixir, Hex (the package manager), Phoenix Framework and PostgreSQL. These are the system requirements and the exact instructions differ between operating systems. Your best bet is to follow the official Phoenix installation guide, which will also help you install Elixir.
BUT, here's the tldr for people on OS X with homebrew:
brew install elixir
Note: by installing Elixir we also get Erlang and mix.
And PostgreSQL...
brew install postgresql
Now let's make sure hex is up to date and install Phoenix with mix
. This is similar to npm install --global
.
mix local.hex
mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
The command to create a new Phoenix application is called mix phx.new
.
As the help page for phx.new
explains, Phoenix comes with a front-end build system called Brunch and other useful stuff for building a front-end. But we're focused on building an API and won't need any of that.
mix phx.new hello --no-brunch --no-html
Tip: use snake_case for application names with multiple words. Like
mix phx.new address_book
.
It will ask you to install dependencies. If you say yes it will run the task mix deps.get
for you. Once it's done it will print something like this in your console:
We are all set! Go into your application by running:
$ cd hello
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
Configure your database in config/dev.exs and run mix ecto.create
.
PostgreSQL database.
Ecto provides a standardised API and a set of abstractions for talking to all the different kinds of databases, so that Elixir developers can query whatever database they’re using by employing similar constructs.
Here's a helpful "tldr" style guide for Ecto https://github.com/parkerl/ecto_query_library
mix ecto.migrate
If everything went well it'll create your database.
Did it say "connection refused"? Check if PostgreSQL is running on your system. With homebrew on OS X you can do
brew services start postgresql
.
Let's start and open the server:
mix phoenix.server
open http://localhost:4000
So now we have everything setup it is time to write our core functionality. We just used two mix tasks (ecto.create and phoenix.server) and to learn more about which mix tasks are available see the Phoenix docs on Mix Tasks. There are tasks to help us get started.
Now, let's create an API where we can create, read, update and delete a post
model. If you do mix phoenix.routes
it will print all routes in your application. If you didn't add any yet, it will have a default /
route that maps to an :index
function.
mix phoenix.gen.json Post posts title:string body:text
It will ask you to add a line to the router. Please do that. Now run mix phoenix.routes
again and you'll see your new routes. The phoenix.gen.json
tasks sets up a complete CRUD API for a model. Let's test it.
- Start the phoenix server (remember how?)
- Open http://localhost:4000/api/posts
See an empty data array? Good. There are no posts, that is why. Let's "seed" the database with some initial data. Add the following lines to priv/repo/seeds.exs
:
alias MyApp.{Repo,Post}
Repo.insert!(%Post{title: "My first post", body: "It works!"})
Repo.insert!(%Post{title: "My second post", body: "It really does work."})
To run it, run mix run priv/repo/seeds.exs
, restart the server and check the /api/posts URL again. See?
curl -i -H "Accept: application/vnd.api+json" -H 'Content-Type:application/vnd.api+json' -X POST -d '{"channel":{"name":"Radio Oskar", }}' http://localhost:4000/channels
curl -H "Content-Type: application/json" -X POST -d '{"channel": {"name": "Jeff Baird"}}' http://localhost:4000/channels
We will deploy this project to the Heroku platform. They offer a free tier we can use, it can be done via the command line and there's a guide we can follow: https://hexdocs.pm/phoenix/heroku.html.
JSONAPI is the name of a specification for building APIs in JSON. This is great because it allows any software that understands JSONAPI to easily work with our API. For instance, Ember.js comes expects JSONAPI by default.
Let's enable it for our Phoenix app. I found at least two options that work with Phoenix.
You can "console.log" with
myVariable
|> IO.inspect
More on https://elixir-lang.org/getting-started/debugging.html. You should look into IEx.pry/0
which seems even more powerful. But I don't get it yet.
Phoenix is structured so it's easy to have multiple pipelines for your application. For instance, you could render some endpoints through JSON and others with GraphQL.
- https://elixirschool.com/
- https://learnxinyminutes.com/docs/elixir/
- https://vimeo.com/152241839
- https://medium.com/codeminer-42/building-a-phoenix-api-d27902a1450a
- https://medium.com/peep-stack/building-a-performant-web-app-with-ember-fastboot-and-phoenix-part-1-fa1241654308
- https://robots.thoughtbot.com/building-a-phoenix-json-api
- https://hexdocs.pm/phoenix/phoenix_mix_tasks.html#phoenix-specific-mix-tasks
Recipes should generally:
- Solve a specific, common problem
- Start with the simplest possible example
- Introduce complexities one at a time
- Link to other docs, rather than re-explaining concepts
- Describe the problem, rather than assuming familiarity
- Explain the process, rather than just the end result
- Explain the pros and cons of your strategy, including when it is and isn’t appropriate
- Mention alternative solutions, if relevant, but leave in-depth explorations to a separate recipe