We passed two arguments to the mix new task: a project name in snake case (hello_world) and the --sup flag. Mix used the project name as our OTP application name and converted it to camel case (HelloWorld) for use in module names when creating our project. The --sup flag let Mix know that we wanted it to create an OTP supervisor and an OTP application callback in our main HelloWorld module.

Follow along in your own environment, or pull down the project from the HelloWorld project page.

Mixing It Up

Moving on into the future, Mix will help us with our dependencies, testing our app, running our app, and more, but how does Mix know enough about our project to help us so much? Our Mixfile, of course! Let’s open our mix.exs to take a look:

version: "0.0.1" sets our application’s version, and elixir: "~> 1.0.0" sets the version of Elixir on which our application depends. All versions in the Elixir world typically follow semantic versioning, so keep that in mind when you’re dealing with them.

deps: deps sets our project’s dependencies with the deps/0 function, which is currently an empty list. Using the Hex Package manager, dependencies are added as two-item tuples like {:dependency, "~> 1.0.0"}.

application/0 provides your project’s OTP application configuration (in keyword list form) to Mix. applications: [:logger] lists the OTP applications on which your project depends. These applications will be started for you automatically when your application runs.

mod: {HelloWorld, []} provides details for OTP to run your application. With Mix building your project’s skeleton, you shouldn’t need to change this, but the first element in the tuple is the module that contains the start/2 callback function for the Application behaviour, which in our case is HelloWorld. If you ever rename your project and/or rename/refactor your modules, be sure to update this line to reflect any changes.

Getting Down to Business

Now for us to get a web application running, we’ll need a server that can speak HTTP, so it’s time for you to build a HTTP/1.1 compliant server. You have fun with that. I’ll wait.

Don’t want to do that just to write a “Hello World” app? I don’t blame you, so instead of writing our own, let’s use Cowboy, a very popular Erlang web server. First thing’s first. Let’s add Cowboy as a dependency in our mix.exs file:

1defpdepsdo2[{:cowboy,"~> 1.0.0"}]3end

and to prepare a bit for the future, we need to add :cowboy under applications in application/0:

Thanks to the power of Hex and S3, that shouldn’t have taken long. We’re now able to implement Cowboy into our project to leverage all of the goodness it provides.

Adding the Fun (but Necessary) Bits

Open up lib/hello_world.ex so we can get to work. Most of the work here will entail getting Cowboy set up so that it will listen for incoming requests. Even though we have set up our mix.exs file to start the :cowboy OTP application, Cowboy doesn’t start HTTP or HTTPS listeners by default and relys on developers (us) to do so.

We’ll create a helper function that defines a set of routes for our application, compile those routes into a form the Cowboy dispatcher knows how to use, and finally, start the HTTP listener with some basic options.

Optionally, we can add a worker child for our supervisor tree to run this function automatically when our application starts, otherwise, the function will need to be run manually, such as in an IEx session.

init/3 handles the bulk of the work here. It let’s Cowboy know what types of connections we wish to handle with this module (HTTP via TCP) and actually creates a response for each incoming request. We use :cowboy_req.reply/4 to build our response with a status code, a list of headers, a response body, and the request itself as Cowboy stashes supporting information about the request in that variable.

handle/2 and terminate/3 aren’t terribly useful in this example, but in other cases, they offer the means to control the lifespan of the Erlang process that is spawned to handle the request. For now, consider them necessary boilerplate code.

Running Our Marvelous Work

Now’s the time for our hard work to pay off. Pass mix as a script to IEx with iex -S mix:

Check that out. Way to go! You now have the knowledge to create a basic web application, but I bet you’re saying something like, “There has to be something more.”

You’re right.

The Something More

While interoperating with Erlang code can provide many benefits,
the resulting Elixir code can end up very non-idiomatic, and the
necessary bits needed to work with Cowboy directly adds some
bloat to our project which would otherwise be fairly lean.

A Specification

Part of what lets Plug is its specification, letting
implementors know what is given to and expected from a plug a.k.a. a
composable module. According to the spec, there are two types of
plugs: function and module.

Function plugs are single functions that follow the signature
(Plug.Conn.t, Plug.opts) :: Plug.Conn.t. In other words, a function
plug accepts a connection and an optional set of options for the plug
to use, which can be any term that is a tuple, atom, integer, float,
or list of the aforementioned types, and returns a connection.

Module plugs operate similarly, requiring a public function call/2
that follows the same signature as a function plug. Module plugs also
require an info/1 function to be use to preprocess options sent to
it. Often, call/2 is invoked as call(conn, info(opts)), especially
(as we’ll see later on) when a plug stack is compiled.

Connection Adapters

With Erlang being great for scalable network programming, it seems
only natural that people wanted to use it for web programming over
the years since Erlang’s release in the mid-1980s. Erlang’s standard
installation comes with a long list of modules, including one for
creating HTTP servers, but the httpd module isn’t really
made for production-level servers.

Because of that, many people have developed some awesome HTTP servers
over the years, including Cowboy, Mochiweb,
Yaws, Elli, and Misultin. Wouldn’t it be
great if we could change the web server used in our application
based on needs or even on a whim? Well, you’re in luck because that
is part of what Plug is trying to achieve with connection adapters.

Currently, Plug only (officially) supports Cowboy,
but there is an open PR for adding an adapter for
Elli, with others probably hidden around the internets. If you ever
wanted to use an Erlang or Elixir web server with Plug that isn’t
supported, all you would need to do is make sure you implemented
the Plug.Conn.Adapter behaviour.
Simple, huh?

Ok, enough with the yammering. Let’s get back into some code.

Route to Your Heart

One benefit with using Plug is Plug.Router, a routing DSL with
some visual similarities to Sinatra. It really takes the
pain away from compiling a dispatch list using the raw, Erlang term
based format that Cowboy expects.

See? Isn’t that better? Plug.Router has macros for handling GET,
POST, PUT, PATCH, DELETE, and OPTIONS requests, with a
general match macro that can be used to handle other HTTP methods
you may require for your application.

Connecting Connections

Looking back at the previous code snippet (the route), you may have
some questions. What’s that conn thing?Why aren’t we doing
anything with it?Why do we just return it? These would be
perfectly good things to ask considering we basically glanced over
the code quickly before.

Essentially, the code let’s us know that we expect our application
to handle GET requests to / (the root). The get macro we use
injects a conn variable into the local with some macro magic (we
will learn a little about this later), and because, for the moment,
we’re lazy and don’t know any better, we let the conn pass
through unmodified as our return expression.

Wait. What’s that? You don’t want to be lazy anymore and want to
send a message to your applications visitors? Let’s say hi!

1get"/"do2conn3|>Plug.Conn.send_resp(200,"Hello world!")4end

Here, we use send_resp/3 from the Plug.Conn module to send a
200 OK response with our message. Plug.Conn has a variety of
functions for reading from and creating new conns. We will touch
on a lot of these as we progress, but if you’re interested now,
take a look to see what it has to offer.