Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
[![erf ci](https://github.com/nomasystems/erf/actions/workflows/ci.yml/badge.svg)](https://github.com/nomasystems/erf/actions/workflows/ci.yml)
[![erf docs](https://github.com/nomasystems/erf/actions/workflows/docs.yml/badge.svg)](https://nomasystems.github.io/erf)

`erf` is a design-first Erlang REST framework. It provides an interface to spawn specification-driven HTTP servers with several automated features that aim to ease the development, operation and maintenance of design-first RESTful services. Its HTTP protocol features are provided as a wrapper of the [elli](https://github.com/elli-lib/elli) HTTP 1.1 server.
`erf` is a design-first Erlang REST framework. It provides an interface to spawn specification-driven HTTP servers with several automated features that aim to ease the development, operation and maintenance of design-first RESTful services.

`erf` supports multiple HTTP server backends:
- [elli](https://github.com/elli-lib/elli) - HTTP/1.1 server
- [cowboy](https://github.com/ninenines/cowboy) - HTTP/1.1 and HTTP/2 server

## What is design-first?

Expand All @@ -18,10 +22,18 @@ Design-first is an approach to API development that prioritises the design of th

1. Design your API using OpenAPI 3.0. For example: [users.openapi.json](examples/users/priv/users.openapi.json).

2. Add `erf` as a dependency in your `rebar3` project.
2. Add `erf` and your chosen HTTP server backend as dependencies in your `rebar3` project.
```erl
%% With elli (HTTP/1.1)
{deps, [
{erf, {git, "git@github.com:nomasystems/erf.git", {branch, "main"}}},
{elli, {git, "https://github.com/elli-lib/elli.git", {branch, "main"}}}
]}.

%% Or with cowboy (HTTP/1.1 and HTTP/2)
{deps, [
{erf, {git, "git@github.com:nomasystems/erf.git", {branch, "main"}}}
{erf, {git, "git@github.com:nomasystems/erf.git", {branch, "main"}}},
{cowboy, {git, "git@github.com:ninenines/cowboy.git", {tag, "2.13.0"}}}
]}.
```

Expand Down Expand Up @@ -102,6 +114,9 @@ init([]) ->
preprocess_middlewares => [users_preprocess],
postprocess_middlewares => [users_postprocess],
port => 8080
%% Optionally specify the HTTP server backend:
%% http_server => {erf_http_server_elli, #{}} % default
%% http_server => {erf_http_server_cowboy, #{}} % for HTTP/2 support
},
UsersChildSpec = {
public_api_server,
Expand Down Expand Up @@ -156,12 +171,7 @@ The configuration is provided as map with the following type spec:
keyfile => binary(),
static_routes => [static_route()],
swagger_ui => boolean(),
min_acceptors => pos_integer(),
accept_timeout => pos_integer(),
request_timeout => pos_integer(),
header_timeout => pos_integer(),
body_timeout => pos_integer(),
max_body_size => pos_integer(),
http_server => {module(), map()},
log_level => logger:level()
}.
```
Expand All @@ -179,14 +189,35 @@ A detailed description of each parameter can be found in the following list:
- `keyfile`: Path to the SSL key file. Defaults to `undefined`.
- `static_routes`: List of routes that serve static files. Defaults to `[]`.
- `swagger_ui`: Boolean flag that enables/disables the Swagger UI. Defaults to `false`.
- `min_acceptors`: Minimum number of acceptor processes. Defaults to `20`.
- `accept_timeout`: Timeout in ms for accepting an incoming request. Defaults to `10000`.
- `request_timeout`: Timeout in ms for receiving more packets when waiting for the request line. Defaults to `60000`.
- `header_timeout`: Timeout in ms for receiving more packets when waiting for the headers. Defaults to `10000`.
- `body_timeout`: Timeout in ms for receiving more packets when waiting for the body. Defaults to `30000`.
- `max_body_size`: Maximum size in bytes for the body of allowed received messages. Defaults to `1024000`.
- `http_server`: HTTP server backend and its configuration. Defaults to `{erf_http_server_elli, #{}}`.
- `log_level`: Severity associated to logged messages. Defaults to `error`.

### HTTP Server Backends

#### elli (default)

```erl
http_server => {erf_http_server_elli, #{
min_acceptors => 20, % Minimum number of acceptor processes
accept_timeout => 10000, % Timeout in ms for accepting requests
request_timeout => 60000, % Timeout in ms for the request line
header_timeout => 10000, % Timeout in ms for headers
body_timeout => 30000, % Timeout in ms for body
max_body_size => 1024000 % Maximum body size in bytes
}}
```

#### cowboy

```erl
http_server => {erf_http_server_cowboy, #{
num_acceptors => 100, % Number of acceptor processes
max_connections => infinity % Maximum number of connections
}}
```

Cowboy supports both HTTP/1.1 and HTTP/2 protocols.

## Callback modules & middlewares

`erf` dynamically generates a router that type check the received requests against the API specification. If the request passes the validation, it is deconstructed and passed to the middleware and callback modules. But, how do those middleware and callback modules must look like?
Expand Down
18 changes: 15 additions & 3 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
]}.

{deps, [
{elli, {git, "https://github.com/elli-lib/elli.git", {branch, "main"}}},
{ndto, {git, "https://github.com/nomasystems/ndto.git", {branch, "main"}}},
{njson, {git, "https://github.com/nomasystems/njson.git", {branch, "main"}}}
]}.
Expand Down Expand Up @@ -33,6 +32,16 @@
{erlfmt, [write]}.

{profiles, [
{elli, [
{deps, [
{elli, {git, "https://github.com/elli-lib/elli.git", {branch, "main"}}}
]}
]},
{cowboy, [
{deps, [
{cowboy, {git, "git@github.com:ninenines/cowboy.git", {tag, "2.13.0"}}}
]}
]},
{examples, [
{project_app_dirs, ["examples/users", "."]},
{shell, [
Expand All @@ -42,6 +51,9 @@
{test, [
{erl_opts, [nowarn_export_all]},
{deps, [
{cowboy, {git, "https://github.com/ninenines/cowboy.git", {tag, "2.13.0"}}},
{elli, {git, "https://github.com/elli-lib/elli.git", {branch, "main"}}},
{gun, {git, "https://github.com/ninenines/gun.git", {tag, "2.1.0"}}},
{meck, {git, "https://github.com/eproxus/meck.git", {branch, "master"}}},
{nct_util, {git, "https://github.com/nomasystems/nct_util.git", {branch, "main"}}}
]}
Expand Down Expand Up @@ -89,8 +101,8 @@
{xref_ignores, [
erf,
{erf_http_server, start_link, 4},
{erf_http_server_elli, handle, 2},
{erf_http_server_elli, handle_event, 3},
erf_http_server_cowboy,
erf_http_server_elli,
{erf_router, handle, 2},
{erf_static, mime_type, 1},
erf_telemetry
Expand Down
6 changes: 1 addition & 5 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
[{<<"elli">>,
{git,"https://github.com/elli-lib/elli.git",
{ref,"c874c42b5d5c1fb7477bc1655134d1de9cbe0223"}},
0},
{<<"ncalendar">>,
[{<<"ncalendar">>,
{git,"https://github.com/nomasystems/ncalendar.git",
{ref,"3a36a9cfe85da197f5032ce9e4c0a4a4dea9e38e"}},
1},
Expand Down
4 changes: 3 additions & 1 deletion src/erf.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
{description, "A design-first Erlang REST Framework"},
{vsn, "0.1.2"},
{registered, []},
{applications, [kernel, stdlib, compiler, syntax_tools, elli, ndto, njson]},
{applications, [kernel, stdlib, compiler, syntax_tools, ndto, njson]},
{optional_applications, [
elli,
cowboy,
telemetry
]},
{env, []}
Expand Down
Loading