2013-06-27 00:02:12 +02:00
|
|
|
Getting started
|
|
|
|
===============
|
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
Setting up a working Erlang application is a little more complex than
|
|
|
|
for most other languages. The reason is that Erlang is designed to
|
|
|
|
build systems and not just simple applications.
|
|
|
|
|
|
|
|
An Erlang system is typically comprised of many different nodes,
|
|
|
|
each containing many different OTP applications, each containing
|
|
|
|
many different modules and running many different processes.
|
|
|
|
Nodes may or may not be identical depending on the nature of the
|
|
|
|
system.
|
|
|
|
|
|
|
|
To get started though, we only need one node that contains your own
|
|
|
|
HTTP application, plus the dependencies that it needs, like Cowboy.
|
|
|
|
To create our node, we need to build what is called a release. A
|
|
|
|
release is a set of files that contain the Erlang VM plus all the
|
|
|
|
applications required to run our node.
|
|
|
|
|
|
|
|
Let's start by creating this application. We will simply call it
|
|
|
|
`hello_erlang`. This application will have the following directory
|
|
|
|
structure:
|
|
|
|
|
|
|
|
```
|
|
|
|
hello_erlang/
|
|
|
|
src/
|
|
|
|
hello_erlang.app.src
|
|
|
|
hello_erlang_app.erl
|
|
|
|
hello_erlang_sup.erl
|
|
|
|
hello_handler.erl
|
|
|
|
erlang.mk
|
|
|
|
Makefile
|
|
|
|
relx.config
|
|
|
|
```
|
|
|
|
|
|
|
|
Once the release is generated, we will also have the following
|
|
|
|
files added:
|
|
|
|
|
|
|
|
```
|
|
|
|
hello_erlang/
|
|
|
|
ebin/
|
|
|
|
hello_erlang.app
|
|
|
|
hello_erlang_app.beam
|
|
|
|
hello_erlang_sup.beam
|
|
|
|
hello_handler.beam
|
|
|
|
_rel/
|
|
|
|
```
|
|
|
|
|
|
|
|
As you can probably guess, the `.app.src` file end up becoming
|
|
|
|
the `.app` file, and the `.erl` files are compiled into `.beam`.
|
|
|
|
Then, the whole release will be copied into the `_rel/` directory.
|
|
|
|
|
|
|
|
The `.app` file contains various informations about the application.
|
|
|
|
It contains its name, a description, a version, a list of modules,
|
|
|
|
default configuration and more.
|
|
|
|
|
|
|
|
Using a build system like [erlang.mk](https://github.com/extend/erlang.mk),
|
|
|
|
the list of modules will be included automatically in the `.app` file,
|
|
|
|
so you don't need to manually put them in your `.app.src` file.
|
|
|
|
|
|
|
|
For generating the release, we will use [relx](https://github.com/erlware/relx)
|
|
|
|
as it is a much simpler alternative to the tool coming with Erlang.
|
|
|
|
|
|
|
|
First, create the `hello_erlang` directory. It should have the same name
|
|
|
|
as the application within it. Then we create the `src` directory inside
|
|
|
|
it, which will contain the source code for our application.
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
$ mkdir hello_erlang
|
|
|
|
$ cd hello_erlang
|
|
|
|
$ mkdir src
|
|
|
|
```
|
2013-06-27 00:02:12 +02:00
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
Let's first create the `hello_erlang.app.src` file. It should be pretty
|
|
|
|
straightforward for the most part. You can use the following template
|
|
|
|
and change what you like in it.
|
2013-06-27 00:02:12 +02:00
|
|
|
|
|
|
|
``` erlang
|
2013-09-07 12:54:55 +02:00
|
|
|
{application, hello_erlang, [
|
|
|
|
{description, "Hello world with Cowboy!"},
|
|
|
|
{vsn, "0.1.0"},
|
|
|
|
{modules, []},
|
|
|
|
{registered, [hello_erlang_sup]},
|
|
|
|
{applications, [
|
|
|
|
kernel,
|
|
|
|
stdlib,
|
|
|
|
cowboy
|
|
|
|
]},
|
|
|
|
{mod, {hello_erlang_app, []}},
|
|
|
|
{env, []}
|
|
|
|
]}.
|
2013-06-27 00:02:12 +02:00
|
|
|
```
|
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
The `modules` line will be replaced with the list of modules during
|
|
|
|
compilation. Make sure to leave this line even if you do not use it
|
|
|
|
directly.
|
|
|
|
|
|
|
|
The `registered` value indicates which processes are registered by this
|
|
|
|
application. You will often only register the top-level supervisor
|
|
|
|
of the application.
|
|
|
|
|
|
|
|
The `applications` value lists the applications that must be started
|
|
|
|
for this application to work. The Erlang release will start all the
|
|
|
|
applications listed here automatically.
|
|
|
|
|
|
|
|
The `mod` value defines how the application should be started. Erlang
|
|
|
|
will use the `hello_erlang_app` module for starting the application.
|
|
|
|
|
|
|
|
The `hello_erlang_app` module is what we call an application behavior.
|
|
|
|
The application behavior must define two functions: `start/2` and
|
|
|
|
`stop/1`, for starting and stopping the application. A typical
|
|
|
|
application module would look like this:
|
|
|
|
|
|
|
|
``` erlang
|
|
|
|
-module(hello_erlang_app).
|
|
|
|
-behavior(application).
|
|
|
|
|
|
|
|
-export([start/2]).
|
|
|
|
-export([stop/1]).
|
|
|
|
|
|
|
|
start(_Type, _Args) ->
|
|
|
|
hello_erlang_sup:start_link().
|
|
|
|
|
|
|
|
stop(_State) ->
|
|
|
|
ok.
|
|
|
|
```
|
|
|
|
|
|
|
|
That's not enough however. Since we are building a Cowboy based
|
|
|
|
application, we also need to initialize Cowboy when we start our
|
|
|
|
application.
|
|
|
|
|
|
|
|
Cowboy does nothing by default.
|
|
|
|
|
2013-06-27 00:02:12 +02:00
|
|
|
Cowboy uses Ranch for handling the connections and provides convenience
|
|
|
|
functions to start Ranch listeners.
|
|
|
|
|
|
|
|
The `cowboy:start_http/4` function starts a listener for HTTP connections
|
|
|
|
using the TCP transport. The `cowboy:start_https/4` function starts a
|
|
|
|
listener for HTTPS connections using the SSL transport.
|
|
|
|
|
|
|
|
Listeners are a group of processes that are used to accept and manage
|
|
|
|
connections. The processes used specifically for accepting connections
|
|
|
|
are called acceptors. The number of acceptor processes is unrelated to
|
|
|
|
the maximum number of connections Cowboy can handle. Please refer to
|
|
|
|
the [Ranch guide](http://ninenines.eu/docs/en/ranch/HEAD/guide/toc)
|
|
|
|
for in-depth information.
|
|
|
|
|
|
|
|
Listeners are named. They spawn a given number of acceptors, listen for
|
|
|
|
connections using the given transport options and pass along the protocol
|
|
|
|
options to the connection processes. The protocol options must include
|
|
|
|
the dispatch list for routing requests to handlers.
|
|
|
|
|
|
|
|
The dispatch list is explained in greater details in the
|
2013-09-07 12:54:55 +02:00
|
|
|
[Routing](routing.md) chapter. For the purpose of this example
|
|
|
|
we will simply map all URLs to our handler `hello_handler`,
|
|
|
|
using the wildcard `_` for both the hostname and path parts
|
|
|
|
of the URL.
|
|
|
|
|
|
|
|
This is how the `hello_erlang_app:start/2` function looks like
|
|
|
|
with Cowboy initialized.
|
2013-06-27 00:02:12 +02:00
|
|
|
|
|
|
|
``` erlang
|
2013-09-07 12:54:55 +02:00
|
|
|
start(_Type, _Args) ->
|
|
|
|
Dispatch = cowboy_router:compile([
|
|
|
|
%% {URIHost, list({URIPath, Handler, Opts})}
|
|
|
|
{'_', [{'_', hello_handler, []}]}
|
|
|
|
]),
|
|
|
|
%% Name, NbAcceptors, TransOpts, ProtoOpts
|
|
|
|
cowboy:start_http(my_http_listener, 100,
|
|
|
|
[{port, 8080}],
|
|
|
|
[{env, [{dispatch, Dispatch}]}]
|
|
|
|
),
|
|
|
|
hello_erlang_sup:start_link().
|
2013-06-27 00:02:12 +02:00
|
|
|
```
|
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
Do note that we told Cowboy to start listening on port 8080.
|
|
|
|
You can change this value if needed.
|
|
|
|
|
|
|
|
Our application doesn't need to start any process, as Cowboy
|
|
|
|
will automatically start processes for every incoming
|
|
|
|
connections. We are still required to have a top-level supervisor
|
|
|
|
however, albeit a fairly small one.
|
|
|
|
|
|
|
|
``` erlang
|
|
|
|
-module(hello_erlang_sup).
|
|
|
|
-behavior(supervisor).
|
|
|
|
|
|
|
|
-export([start_link/0]).
|
|
|
|
-export([init/1]).
|
|
|
|
|
|
|
|
start_link() ->
|
|
|
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
|
|
|
|
|
|
|
init([]) ->
|
|
|
|
{ok, {{one_for_one, 10, 10}, []}}.
|
|
|
|
```
|
|
|
|
|
|
|
|
Finally, we need to write the code for handling incoming requests.
|
|
|
|
|
2013-06-27 00:02:12 +02:00
|
|
|
Cowboy features many kinds of handlers. For this simple example,
|
|
|
|
we will just use the plain HTTP handler, which has three callback
|
2013-09-07 12:54:55 +02:00
|
|
|
functions: `init/3`, `handle/2` and `terminate/3`. You can find more
|
|
|
|
information about the arguments and possible return values of these
|
|
|
|
callbacks in the
|
2013-06-27 00:02:12 +02:00
|
|
|
[cowboy_http_handler function reference](http://ninenines.eu/docs/en/cowboy/HEAD/manual/cowboy_http_handler).
|
2013-09-07 12:54:55 +02:00
|
|
|
|
|
|
|
Our handler will only send a friendly hello back to the client.
|
2013-06-27 00:02:12 +02:00
|
|
|
|
|
|
|
``` erlang
|
2013-09-07 12:54:55 +02:00
|
|
|
-module(hello_handler).
|
|
|
|
-behavior(cowboy_http_handler).
|
2013-06-27 00:02:12 +02:00
|
|
|
|
|
|
|
-export([init/3]).
|
|
|
|
-export([handle/2]).
|
|
|
|
-export([terminate/3]).
|
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
init(_Type, Req, _Opts) ->
|
2013-06-27 00:02:12 +02:00
|
|
|
{ok, Req, undefined_state}.
|
|
|
|
|
|
|
|
handle(Req, State) ->
|
2013-09-07 12:54:55 +02:00
|
|
|
{ok, Req2} = cowboy_req:reply(200, [
|
|
|
|
{<<"content-type">>, <<"text/plain">>}
|
|
|
|
], <<"Hello World!">>, Req),
|
2013-06-27 00:02:12 +02:00
|
|
|
{ok, Req2, State}.
|
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
terminate(_Reason, _Req, _State) ->
|
2013-06-27 00:02:12 +02:00
|
|
|
ok.
|
|
|
|
```
|
|
|
|
|
|
|
|
The `Req` variable above is the Req object, which allows the developer
|
2013-09-07 12:54:55 +02:00
|
|
|
to obtain information about the request and to perform a reply.
|
|
|
|
Its usage is documented in the
|
|
|
|
[cowboy_req function reference](http://ninenines.eu/docs/en/cowboy/HEAD/manual/cowboy_req).
|
|
|
|
|
|
|
|
The code for our application is ready, so let's build a release!
|
|
|
|
|
|
|
|
First we need to download `erlang.mk`.
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
$ wget https://raw.github.com/extend/erlang.mk/master/erlang.mk
|
|
|
|
$ ls
|
|
|
|
src/
|
|
|
|
erlang.mk
|
|
|
|
```
|
|
|
|
|
|
|
|
Then we need to create a Makefile that will include `erlang.mk`
|
|
|
|
for building our application. We need to define the Cowboy
|
|
|
|
dependency in the Makefile. Thankfully `erlang.mk` already
|
|
|
|
knows where to find Cowboy as it features a package index,
|
|
|
|
so we can just tell it to look there.
|
|
|
|
|
|
|
|
``` Makefile
|
|
|
|
PROJECT = hello_erlang
|
|
|
|
|
|
|
|
DEPS = cowboy
|
|
|
|
dep_cowboy = pkg://cowboy master
|
|
|
|
|
|
|
|
include erlang.mk
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that when creating production nodes you will most likely
|
|
|
|
want to use a specific version of Cowboy instead of `master`,
|
|
|
|
and properly test your release every time you update Cowboy.
|
|
|
|
|
|
|
|
If you type `make` in a shell now, your application should build
|
|
|
|
as expected. If you get compilation errors, double check that you
|
|
|
|
haven't made any typo when creating the previous files.
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
$ make
|
|
|
|
```
|
|
|
|
|
|
|
|
That's not all however, as we want to create a working release.
|
|
|
|
For that purpose we will need `relx`. You can download it directly
|
|
|
|
[from Github](https://github.com/erlware/relx). After downloading
|
|
|
|
it, you will need to build it using `make`, which should give
|
|
|
|
you a `relx` executable that you can then put in your `$PATH`.
|
|
|
|
You only need to do this once.
|
|
|
|
|
|
|
|
We are almost ready to build the release. All that's left is
|
|
|
|
the `relx.config` file! In it, we only need to tell `relx` that
|
|
|
|
we want the release to include the `hello_erlang` application,
|
|
|
|
and that we want an extended start script for convenience.
|
|
|
|
`relx` will figure out which other applications are required
|
|
|
|
by looking into the `.app` files for dependencies.
|
|
|
|
|
|
|
|
``` erlang
|
|
|
|
{release, {hello_erlang, "1"}, [hello_erlang]}.
|
|
|
|
{extended_start_script, true}.
|
|
|
|
```
|
|
|
|
|
|
|
|
The `release` value is used to specify the release name, its
|
|
|
|
version, and the applications to be included.
|
|
|
|
|
|
|
|
We can now build and start the release.
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
$ relx
|
|
|
|
$ ./_rel/bin/hello_erlang console
|
|
|
|
```
|
|
|
|
|
|
|
|
If you then access `http://localhost:8080` using your browser,
|
|
|
|
you should receive a nice greet!
|
2013-06-27 00:02:12 +02:00
|
|
|
|
2013-09-07 12:54:55 +02:00
|
|
|
You can find many more examples in the `examples/` directory
|
|
|
|
of the Cowboy repository.
|