Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save oskarrough/2e0f1c97a3165b73f11e3f023a663ab0 to your computer and use it in GitHub Desktop.
Save oskarrough/2e0f1c97a3165b73f11e3f023a663ab0 to your computer and use it in GitHub Desktop.

How to build a JSON API with Elixir & Phoenix

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)

Terminology

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.

Mix and Hex

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.

Installing everything

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

Configuring the database

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.

Setting up CRUD for a model

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.

  1. Start the phoenix server (remember how?)
  2. 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?

Adding data

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

Deploying

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.

Enabling JSON API

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.

Using JSONAPI module

Using ja_serializer module

CORS

Debugging

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.

GraphQL

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.

Editor integrations

References

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment