How do you I create a simple web server with Elixir using Cowboy and Plug?

Last updated

This post is also available in different formats so you can read on the go or share it around!

You’ll often hear talk about Phoenix a lot in the Elixir ecosystem but there are a few other options for web servers. We’re going to take a look at what underpins Phoenix and see how to create a simple web server in Elixir. We’ll use plug_cowboy which combines the Erlang web server Cowboy and a nice adapter Plug.

What we’re making

We’re going to make what can barely be called a web server, it’s simply going to respond with “Hello World” over HTTP/1.1. It’s a humble start but from here, it’s easy to add routing, serve static assets, make your own API and more.

If you’d like to see the code right away - take a look at the example repo here.

Creating a simple server

We’ll create a new project, add the only dependency we need - plug_cowboy, then do a little bit of setup.

Create a new project

Let’s start with a new app: mix new simple_plug_rest --sup, this will create a barebones Elixir project.

Now, installplug_cowboy in mix.exs like so:

def deps do
  [
    {:plug_cowboy, "~> 2.0"}
  ]
end

You can update the dependencies afterwards by running mix deps.get.

Create a simple Plug

A plug is a specification for our web server, let’s make a simple plug based on that simply replies with “Hello World”.

defmodule SimplePlugRest do
  @moduledoc """
  A Plug that always responds with a string
  """
  import Plug.Conn

  def init(options) do
    options
  end

  @doc """
  Simple route that returns a string
  """
  @spec call(Plug.Conn.t(), any) :: Plug.Conn.t()
  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello World")
  end
end

Setup Application:

The final piece of the puzzle is to start the Cowboy server as a supervised process and tell plug_cowboy which plug to use.

defmodule SimplePlugRest.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Start `SimplePlugRest` and listen on port 3000
      {Plug.Cowboy, scheme: :http, plug: SimplePlugRest, options: [port: 3000]}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: SimplePlugRest.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Start your web server up by running mix run --no-halt then visit localhost:3000 in your browser! It’s not pretty, but it works.

What about JSON?

One of the most common response types nowadays is JSON. If you’d like, you can leverage the jason package to encode a map in Elixir.

To get started, add {:jason, "~> 1.1"} to your mix.exs deps.

Then use Jason.encode! to encode the data. If you were to build upon this, a simple helper function could do make creating a json payload easier.

In the meantime, the call method will look something like this:

def call(conn, _opts) do
  body = Jason.encode!(%{hello: "world"})

  conn
  |> put_resp_content_type("application/json")
  |> send_resp(200, body)
end

That’s it. You now have the building blocks for creating a web server in Elixir with some easy to use libraries.

Resources

Seth Corker

A Fullstack Software Engineer working with React and Django. My main focus is JavaScript specialising in frontend UI with React. I like to explore different frameworks and technologies in my spare time. Learning languages (programming and real life) is a blast.