Skip to content

Commit 164f23e

Browse files
Move overview to its own .md
(and reference it from README.md)
1 parent bde4da3 commit 164f23e

File tree

3 files changed

+222
-42
lines changed

3 files changed

+222
-42
lines changed

OVERVIEW.md

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Elli - Overview
2+
3+
Copyright (c) 2012-2016 Knut Nesheim, 2016-2018 elli-lib team
4+
5+
__Version:__ 3.3.0
6+
7+
__Authors:__ Knut Nesheim, elli-lib team.
8+
9+
Erlang web server for HTTP APIs
10+
11+
## Features
12+
13+
Here's the features Elli _does_ have:
14+
15+
* [Rack][]-style request-response. Your handler function gets a
16+
complete request and returns a complete response. There's no
17+
messaging, no receiving data directly from the socket, no writing
18+
responses directly to the socket. It's a very simple and
19+
straightforward API. Have a look at [`elli_example_callback`](elli_example_callback.html)
20+
for examples.
21+
22+
* Middlewares allow you to add useful features like compression,
23+
encoding, stats, but only have it used when needed. No features you
24+
don't use on the critical path.
25+
26+
* Short-circuiting of responses using exceptions, allows you to use
27+
"assertions" that return for example 403 permission
28+
denied. `is_allowed(Req) orelse throw({403, [], <<"Permission
29+
denied">>})`.
30+
31+
* Every client connection gets its own process, isolating the failure
32+
of a request from another. For the duration of the connection, only
33+
one process is involved, resulting in very robust and efficient
34+
code.
35+
36+
* Binaries everywhere for strings.
37+
38+
* Instrumentation inside the core of the webserver, triggering user
39+
callbacks. For example when a request completes, the user callback
40+
gets the `request_complete` event which contains timings of all the
41+
different parts of handling a request. There's also events for
42+
clients unexpectedly closing a connection, crashes in the user
43+
callback, etc.
44+
45+
* Keep alive, using one Erlang process per connection only active
46+
when there is a request from the client. Number of connections is
47+
only limited by RAM and CPU.
48+
49+
* Chunked transfer in responses for real-time push to clients
50+
51+
* Basic pipelining. HTTP verbs that does not have side-effects(`GET`
52+
and `HEAD`) can be pipelined, ie. a client supporting pipelining
53+
can send multiple requests down the line and expect the responses
54+
to appear in the same order as requests. Elli processes the
55+
requests one at a time in order, future work could make it possible
56+
to process them in parallel.
57+
58+
* SSL using built-in Erlang/OTP ssl, nice for low volume admin
59+
interfaces, etc. For high volume, you should probably go with
60+
nginx, stunnel or ELB if you're on AWS.
61+
62+
* Implement your own connection handling, for WebSockets, streaming
63+
uploads, etc. See [`elli_example_callback_handover`](elli_example_callback_handover.html).
64+
65+
## Extensions
66+
67+
Here's some ready-to-use extensions for Elli.
68+
69+
* [elli_access_log](https://github.com/elli-lib/elli_access_log):
70+
Access log
71+
* [elli_basicauth](https://github.com/elli-lib/elli_basicauth):
72+
Basic auth
73+
* [elli_chatterbox](https://github.com/elli-lib/elli_chatterbox):
74+
HTTP/2 support
75+
* [elli_cloudfront](https://github.com/elli-lib/elli_cloudfront):
76+
CloudFront signed URLs
77+
* [elli_cookie](https://github.com/elli-lib/elli_cookie):
78+
Cookies
79+
* [elli_date](https://github.com/elli-lib/elli_date):
80+
"Date" header
81+
* [elli_fileserve](https://github.com/elli-lib/elli_fileserve):
82+
Static content
83+
* [elli_prometheus](https://github.com/elli-lib/elli_prometheus):
84+
Prometheus
85+
* [elli_stats](https://github.com/elli-lib/elli_stats):
86+
Real-time statistics dashboard
87+
* [elli_websockets](https://github.com/elli-lib/elli_websocket):
88+
WebSockets
89+
* [elli_xpblfe](https://github.com/elli-lib/elli_xpblfe):
90+
X-Powered-By LFE
91+
92+
You can also find a more complete list at <https://github.com/elli-lib>.
93+
94+
## About
95+
96+
From operating and debugging high-volume, low-latency apps we have
97+
gained some valuable insight into what we want from a webserver. We
98+
want simplicity, robustness, performance, ease of debugging,
99+
visibility into strange client behaviour, really good instrumentation
100+
and good tests. We are willing to sacrifice almost everything, even
101+
basic features to achieve this.
102+
103+
With this in mind we looked at the big names in the Erlang
104+
community: [Yaws][], [Mochiweb][], [Misultin][] and [Cowboy][]. We
105+
found [Mochiweb][] to be the best match. However, we also wanted to
106+
see if we could take the architecture of [Mochiweb][] and improve on
107+
it. Elli takes the acceptor-turns-into-request-handler idea found
108+
in [Mochiweb][], the binaries-only idea from [Cowboy][] and the
109+
request-response idea from [WSGI][]/[Rack][] (with chunked transfer
110+
being an exception).
111+
112+
On top of this we built a handler that allows us to write HTTP
113+
middleware modules to add practical features, like compression of
114+
responses, HTTP access log with timings, a real-time statistics
115+
dashboard and chaining multiple request handlers.
116+
117+
## Aren't there enough webservers in the Erlang community already?
118+
119+
There are a few very mature and robust projects with steady
120+
development, one recently ceased development and one new kid on the
121+
block with lots of interest. As Elli is not a general purpose
122+
webserver, but more of a specialized tool, we believe it has a very
123+
different target audience and would not attract effort or users away
124+
from the big names.
125+
126+
## Why another webserver? Isn't this just the NIH syndrome?
127+
128+
[Yaws][], [Mochiweb][], [Misultin][], and [Cowboy][] are great
129+
projects, hardened over time and full of very useful features for web
130+
development. If you value developer productivity, [Yaws][] is an
131+
excellent choice. If you want a fast and lightweight
132+
server, [Mochiweb][] and [Cowboy][] are excellent choices.
133+
134+
Having used and studied all of these projects, we believed that if we
135+
merged some of the existing ideas and added some ideas from other
136+
communities, we could create a core that was better for our use cases.
137+
138+
It started out as an experiment to see if it is at all possible to
139+
significantly improve and it turns out that for our particular use
140+
cases, there is enough improvement to warrant a new project.
141+
142+
## What makes Elli different?
143+
144+
Elli has a very simple architecture. It avoids using more processes
145+
and messages than absolutely necessary. It uses binaries for
146+
strings. The request-response programming model allows middlewares to
147+
do much heavy lifting, so the core can stay very simple. It has been
148+
instrumented so as a user you can understand where time is spent. When
149+
things go wrong, like the client closed the connection before you
150+
could send a response, you are notified about these things so you can
151+
better understand your client behaviour.
152+
153+
## Performance
154+
155+
"Hello World!" micro-benchmarks are really useful when measuring the
156+
performance of the webserver itself, but the numbers usually do more
157+
harm than good when released. I encourage you to run your own
158+
benchmarks, on your own hardware. Mark Nottingham has some
159+
[very good pointers](http://www.mnot.net/blog/2011/05/18/http_benchmark_rules)
160+
about benchmarking HTTP servers.
161+
162+
[Yaws]: https://github.com/klacke/yaws
163+
[Mochiweb]: https://github.com/mochi/mochiweb
164+
[Misultin]: https://github.com/ostinelli/misultin
165+
[Cowboy]: https://github.com/ninenines/cowboy
166+
[WSGI]: https://www.python.org/dev/peps/pep-3333/
167+
[Rack]: https://github.com/rack/rack

README.md

+52-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# elli - Erlang web server for HTTP APIs
1+
# Elli - Erlang web server for HTTP APIs
22

33
[![Hex.pm](https://img.shields.io/hexpm/v/elli.svg)](https://hex.pm/packages/elli)
44
[![Documentation](https://img.shields.io/badge/docs-edown-green.svg)](doc/README.md)
@@ -8,37 +8,36 @@
88
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
99

1010
Elli is a webserver you can run inside your Erlang application to
11-
expose an HTTP API. Elli is aimed exclusively at building
11+
expose an HTTP API. It is aimed exclusively at building
1212
high-throughput, low-latency HTTP APIs. If robustness and performance
13-
is more important than general purpose features, then `elli` might be
13+
is more important to you than general purpose features, then Elli might be
1414
for you. If you find yourself digging into the implementation of a
15-
webserver, `elli` might be for you. If you're building web services,
16-
not web sites, then `elli` might be for you.
15+
webserver, then Elli might be for you. If you're building web services,
16+
not web sites, then Elli might be for you.
1717

1818
Elli requires OTP 20.0 or newer.
1919

2020
## Installation
2121

22-
To use `elli` you will need a working installation of Erlang 18.0 (or later).
23-
24-
Add `elli` to your application by adding it as a dependency to your
25-
[`rebar.config`](http://www.rebar3.org/docs/configuration):
22+
Add `elli` to your application as a dependency to your
23+
[`rebar.config`](https://www.rebar3.org/docs/configuration):
2624

2725
```erlang
2826
{deps, [
29-
%% ...
30-
{elli, "3.0.0"}
27+
{elli, "3.3.0"}
3128
]}.
3229
```
3330

34-
Afterwards you can run:
31+
Afterwards, to compile it, you can run:
3532

3633
```console
3734
rebar3 compile
3835
```
3936

4037
## Usage
4138

39+
To boot Elli inside an Erlang shell, run:
40+
4241
```console
4342
rebar3 shell
4443
```
@@ -53,67 +52,80 @@ rebar3 shell
5352
### Callback Module
5453

5554
The best source to learn how to write a callback module
56-
is [`elli_example_callback.erl`](elli_example_callback.html). There are a bunch
55+
is [`elli_example_callback`](elli_example_callback.html).
56+
There are also a bunch
5757
of examples used in the tests as well as descriptions of all the events.
5858

59-
A minimal callback module could look like this:
59+
A minimal callback module looks something like this:
6060

6161
```erlang
6262
-module(elli_minimal_callback).
63-
-export([handle/2, handle_event/3]).
63+
-behaviour(elli_handler).
6464

6565
-include_lib("elli/include/elli.hrl").
66-
-behaviour(elli_handler).
66+
67+
-export([handle/2, handle_event/3]).
6768

6869
handle(Req, _Args) ->
6970
%% Delegate to our handler function
70-
handle(Req#req.method, elli_request:path(Req), Req).
71+
Method = Req#req.method,
72+
Path = elli_request:path(Req),
73+
handle(Method, Path, Req).
7174

72-
handle('GET',[<<"hello">>, <<"world">>], _Req) ->
75+
handle('GET' = _Method, [<<"hello">>, <<"world">>] = _Path, _Req) ->
7376
%% Reply with a normal response. `ok' can be used instead of `200'
7477
%% to signal success.
75-
{ok, [], <<"Hello World!">>};
78+
StatusCode = ok,
79+
Headers = [],
80+
Body = <<"Hello World!">>,
81+
{StatusCode, Headers, Body};
7682

77-
handle(_, _, _Req) ->
83+
handle(_Method, _Path, _Req) ->
7884
{404, [], <<"Not Found">>}.
7985

80-
%% @doc Handle request events, like request completed, exception
86+
%% @doc Handle request events: request completed, exception
8187
%% thrown, client timeout, etc. Must return `ok'.
8288
handle_event(_Event, _Data, _Args) ->
8389
ok.
8490
```
8591

86-
### Supervisor Childspec
92+
### Supervisor ChildSpec
8793

8894
To add `elli` to a supervisor you can use the following example and adapt it to
8995
your needs.
9096

9197
```erlang
92-
-module(fancyapi_sup).
98+
-module(elli_minimal_sup).
9399
-behaviour(supervisor).
94-
-export([start_link/0]).
95-
-export([init/1]).
96100

97-
start_link() ->
98-
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
101+
-export([start_link/0, init/1]).
99102

100-
init([]) ->
101-
ElliOpts = [{callback, fancyapi_callback}, {port, 3000}],
103+
start_link() ->
104+
SupName = {local, ?MODULE},
105+
Module = ?MODULE,
106+
Args = [],
107+
supervisor:start_link(SupName, Module, Args).
108+
109+
init([] = _Args) ->
110+
ElliOpts = [
111+
{callback, elli_minimal_callback},
112+
{port, 3000}
113+
],
102114
ElliSpec = {
103-
fancy_http,
104-
{elli, start_link, [ElliOpts]},
105-
permanent,
106-
5000,
107-
worker,
108-
[elli]},
109-
110-
{ok, { {one_for_one, 5, 10}, [ElliSpec]} }.
115+
_Id = elli_minimal_http,
116+
_Start = {elli, start_link, [ElliOpts]},
117+
_Restart = permanent,
118+
_Shutdown = 5000,
119+
_Worker = worker,
120+
_Modules = [elli]},
121+
122+
{ok, {{_Strategy = one_for_one, _Intensity = 5, _Period = 10}, [ElliSpec]} }.
111123
```
112124

113-
## Further Reading
125+
## Further reading
114126

115-
For more information about the features and design philosophy of `elli` check
116-
out the [overview](doc/README.md).
127+
For more information about the features and design philosophy of Elli check
128+
out the [`overview`](overview.html).
117129

118130
## License
119131

rebar.config

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
]}.
3333
{ex_doc, [
3434
{extras, [
35+
"README.md",
36+
"OVERVIEW.md",
3537
"CHANGELOG.md",
36-
"LICENSE",
37-
"README.md"
38+
"LICENSE"
3839
]},
3940
{main, "README.md"},
4041
{source_url, "https://github.com/elli-lib/elli"}

0 commit comments

Comments
 (0)