Thanks for the responses.
You still have to load&start your application and its dependencies.
Yes, getting all the paths correct to all the source file dependencies as well as your own source files makes compiling and starting everything non-trivial.
I ended up following a tutorial on setting up cowboy in a Docker container along with rebar3. I’m not using a Docker container, so what I ended up with is a rebar3 app with cowboy as a dependency. Thereafter, when I execute rebar3 shell
, that starts a cowboy server and opens a shell in the terminal window. Then if I go into another terminal window and send a request to the url specified in my cowboy code, I get the expected response.
Here are the steps:
$ rebar3 new app my_cowboy_server
$ cd my_cowboy_server
Add cowboy as a dependency–in the file my_cowboy_server/rebar.config
:
{erl_opts, [debug_info]}.
{deps, [
{cowboy, "2.10.0"}
]}.
{shell, [
% {config, "config/sys.config"},
{apps, [my_cowboy_server]}
]}.
You don’t have to add ranch
or cow_lib
as a dependency.
Add cowboy to the list of applications that need to be started before your app–in the file my_cowboy_server/src/my_cowboy.app.src
:
{application, my_cowboy_server,
[{description, "An OTP application"},
{vsn, "0.1.0"},
{registered, []},
{mod, {my_cowboy_server_app, []}},
{applications,
[kernel,
stdlib,
cowboy
]},
{env,[]},
{modules, []},
{licenses, ["Apache-2.0"]},
{links, []}
]}.
Add your routes to the file my_cowboy_server/src/my_cowboy_server_app.erl
:
start(_StartType, _StartArgs) ->
Dispatch = cowboy_router:compile([
{'_', [{"/greet", hello_handler, []}]}
]),
{ok, _} = cowboy:start_clear(my_http_listener,
[{port, 8080}],
#{env => #{dispatch => Dispatch}}
),
my_cowboy_server_sup:start_link().
Create the file my_cowboy_server/src/hello_handler.erl
:
-module(hello_handler).
-behavior(cowboy_handler).
-export([init/2]).
init(Req0, State) ->
Req = cowboy_req:reply(200,
#{<<"content-type">> => <<"text/plain">>},
<<"Hello Erlang!\r\n">>,
Req0),
{ok, Req, State}.
Then in one terminal window, I can execute:
my_cowboy_server$ rebar3 shell
and any output in my cowboy code will appear in that terminal window, for instance if I have this code:
-module(my_cowboy_server_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
io:format("[ME]: inside start()~n"), % <======HERE
Dispatch = cowboy_router:compile([
{'_', [{"/greet", hello_handler, []}]}
]),
...
...
I see:
my_cowboy_server$ rebar3 shell
rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling my_cowboy_server
Erlang/OTP 26 [erts-14.1.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]
Eshell V14.1.1 (press Ctrl+G to abort, type help(). for help)
[ME]: inside start() <===========THIS
===> Booted cowlib
===> Booted ranch
===> Booted cowboy
===> Booted my_cowboy_server
1>
Then I can open another terminal window and send a request to the cowboy server, for instance:
$ curl "http://localhost:8080/greet"
Hello Erlang!
If you want/need to use the template generating capabilities of Erlang.mk, for instance to create hello_handler.erl
, you could follow the cowboy Getting Started guide and create the hello_erlang release, then any time you need a template switch into that directory, generate the template, copy it, modify the module name, etc., then move it into your rebar3 app.
The command rebar3 shell
compiles and executes the same code in about 1 second compared to 30-40 seconds for Erlang.mk. Of course, rebar3 shell
is not creating a release, but if you want to experiment with cowboy, then rebar3 seems like the best way to quickly compile and execute your code.