It is interesting to learn things from scratch. Coming from Ruby background, I was curious what is the equivalent of Sinatra in Elixir. It’s called Plug. It is what Phoenix build on top of.

Using Sinatra, we can write a quick and simple web server with the following code:

require 'sinatra'
require 'json'

get '/' do
  content_type :json
  JSON({message: "Hello World"})
end

How can we achive that in Elixir? With Plug and Cowboy.

Setup

NOTE: This article is based on Elixir v1.7.3

First of all, let’s create a mix project and change directory into it.

mix new sample_app
cd sample_app

Open mix.exs file with your favourite editor. And add the dependencies as follow:

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

We add Plug and Cowboy as dependencies because Cowboy act as a web server and Plug on the other hand, act as a connection adapter to the web server.

Before we proceed, let’s get all the dependencies first by running the following command:

mix deps.get

Using Plug

Plug can be complicated if we don’t understand it. The best way to understand it, is to, read the documentation (In fact, all the steps mentioned above and below are already available in the documentation).

So to get a taste of how Plug works, let’s just copy and paste the code from the documentation and make some changes. Let’s create lib/my_plug.ex and and add in the code.

touch lib/my_plug.ex
defmodule SampleApp.MyPlug do
  import Plug.Conn

  def init(options) do
    # initialize options

    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end

Let’s try to run the code.

iex -S mix

iex(1)> {:ok, _} = Plug.Adapters.Cowboy2.http SampleApp.MyPlug, []

Now let’s go and visit http://localhost:4000. You should be able to see a “Hello World” on your browser. We just start the cowboy web server in iex, by passing it our Plug and [] empty arguments.

That’s all

Yes, you have wrote a simple web server using Elixir.

Wait, wait, but how can I run my server through command line? I have to run iex -S mix and start the Cowboy server manually every time?

Nope. We can make it an OTP application. So that we just need to run mix run --no-halt or iex -S mix and the cowboy server will boot up itself.

Basic of OTP Application

OTP application is basically a component that has predefined behaviour. It can be started, loaded or stopped. To create an OTP application in Elixir, we use the Application module and implements some of the expected behavior. For more you can always refer to the documentation of Application.

So let’s create a simple application first.

touch lib/app.ex
defmodule SampleApp.App do
  use Application
  def start(_type, _args) do
    IO.puts "Starting application"
    children = []
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

Now if you run mix run --no-halt, you still won’t see the “Starting application” output yet. This is because we haven’t configure our mix.exs yet.

To make mix run our application, we have to add the following code into mix.exs:

def application do
  [
    extra_applications: [:logger],
    mod: {SampleApp.App, []} # Add in this line of code
  ]
end

Now, if we run mix run --no-halt, we can finally see the “Starting application…” output. It also means we have sucessfully start an OTP application.

Starting Cowboy Server automatically

Remember how we run our cowboy server in iex?

iex -S mix

iex(1)> {:ok, _} = Plug.Adapters.Cowboy2.http SampleApp.MyPlug, []

Now after knowing how to start our OTP application with mix run --no-halt or iex -S mix, we need to start our cowboy server after our application is started.

To do this, we need to modify the start/2 method in the app.ex.

def start(_type, _args) do
  children = [
    # Define workers and child supervisors to be supervised
    Plug.Adapters.Cowboy2.child_spec(scheme: :http, plug: SampleApp.MyPlug, options: [port: 4000])
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end

What we are doing here is to specify the child spec of the child process, which is our cowboy. A child specification basically tell the supervisor how to start, restart or shutdown the child process. The above code is also mentioned in the documentation of Plug under Supervised handlers.

Now, if we run the mix run --no-halt, and visit http://localhost:4000.

Our web application is now online.

Summary

If you’re a beginner to OTP or Elixir, there are a lots of stuff underneath that I didn’t cover well. This is my first blog post on Elixir. It might be lacking. So here are some other resources you can refer to:

The source code of the project is available at GitHub.


Footnote

  1. To be honest, Elixir School does a better job in explaining this topic. The way I’m writing is based on how my thought process flow, so it might be different and unstructured. This post also covers less topics about using Plug compared to Elixir School.