# `simpler_cowboy_rest` [![CI][ci-img]][ci]
[ci]: https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/actions
[ci-img]: https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/actions/workflows/ci.yml/badge.svg
A simpler (and opinionated) `cowboy_rest` application.
## The behaviour
### Context
[`cowboy_rest`](https://github.com/ninenines/cowboy/blob/master/src/cowboy_rest.erl),
a behaviour presented by [`cowboy`](https://github.com/ninenines/cowboy), allows you
to define handlers for HTTP routes and verbs.
### Motivation
Since it's possible many of your handlers will implement similar behaviour-implementing
callbacks, this application implements a generic way to have a "higher-level" behaviour without
the need for declaring generic calls that all your callbacks have to call, or using
solutions like [inaka/mixer](https://github.com/inaka/mixer), which are based
on parse transforms. This is available via configuration key (module) `shared_impl`,
where you'll implement a `simpler_cowboy_rest` behaviour to deal with shared implementation details.
(the [example](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/tree/main/example)
makes simple use of this concept).
It also sprinkles some opinions, like having verbs visible in the route metadata,
considering `application/json` the default data exchange "protocol", and naming
verbs as methods, like `put`, and `delete` (it even "gets rid" of `delete_resource/2`).
### Details/opinions/caveats
"`% per route extensions`" assumes each of your handlers handles unique
verbs (e.g. no two GET for similar routes implemented in the same module).
Functions exported with `/3` (first argument being `default`) is where you'll define/maintain
generic callback definitions. To add a generic callback, expose a `/2` -equivalent.
Because we're using `erlang:function_exported` to check if a function is exported,
not calling the function directly we use `:module_info` to force code load,
otherwise the first call to each route would "fail".
### How to
Declare your dispatch handlers (and start the server) with something like the following
```erlang
TransOpts = [
{port, 8080}
],
Routes = [
{"/health", #{
methods => [<<"GET">>],
are_dispatched_to => simpler_cowboy_rest_example_health
}},
{"/kv[/[:k]]", #{
methods => [<<"PUT">>, <<"GET">>, <<"POST">>, <<"DELETE">>],
are_dispatched_to => simpler_cowboy_rest_example_kv
}}
],
{ok, _} = simpler_cowboy_rest:start(Routes, TransOpts).
```
#### Logger metadata
The application saves logger metadata key `simpler_cowboy_rest_dispatched_to` as an MFA
tuple that can be recovered for tracing your logging entries.
## The project
### Changelog
A complete changelog can be found under [CHANGELOG.md](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/blob/main/CHANGELOG.md).
### Code of Conduct
This project's code of conduct is made explicit in [CODE_OF_CONDUCT.md](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/blob/main/CODE_OF_CONDUCT.md).
### Contributing
First of all, thank you for contributing with your time and patience.
If you want to request a new feature make sure to
[open an issue](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/issues) so we can
discuss it first.
Bug reports and questions are also welcome, but do check you're using the latest version of the
plugin - if you found a bug - and/or search the issue database - if you have a question, since it
might have already been answered before.
Contributions will be subject to the MIT License.
You will retain the copyright.
For more information check out [CONTRIBUTING.md](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/blob/main/CONTRIBUTING.md).
### License
License information can be found inside [LICENSE.md](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/blob/main/LICENSE.md).
### Security
This project's security policy is made explicit in [SECURITY.md](https://github.com/paulo-ferraz-oliveira/simpler_cowboy_rest/blob/main/SECURITY.md).
### Running tests
Start the example application, in folder `example`, in a `rebar3`/Erlang shell, with
`rebar3 shell`.
Run tests with `shelltest example.test` inside folder `test`. You'll need to have
[shelltestrunner](https://github.com/simonmichael/shelltestrunner) installed.
Example output:
```console
➜ tests git:(main) shelltest example.test
:example.test:1: [OK]
:example.test:2: [OK]
:example.test:3: [OK]
:example.test:4: [OK]
:example.test:5: [OK]
:example.test:6: [OK]
:example.test:7: [OK]
:example.test:8: [OK]
:example.test:9: [OK]
Test Cases Total
Passed 9 9
Failed 0 0
Total 9 9
```