# Boing
A key-based debouncer with built-in implementations for `Tesla` and `Req` HTTP clients.
For HTTP requests, GET requests to the same URL are debounced, all other requests are unaffected.
Debounced requests are rejected client-side and the HTTP request is not made.
## Example
### Tesla
```elixir
iex(1)> client = Tesla.client([Boing.TeslaMiddleware])
%Tesla.Client{...}
iex(2)> for _ <- 1..3, do: spawn(fn -> dbg(Tesla.get(client, "http://example.com")) end)
[#PID<0.208.0>, #PID<0.209.0>, #PID<0.210.0>]
Tesla.get(client, "http://example.com") #=> {:error, [debounced: "http://example.com"]}
Tesla.get(client, "http://example.com") #=> {:error, [debounced: "http://example.com"]}
Tesla.get(client, "http://example.com") #=> {:ok, %Tesla.Env{body: ...}}
```
For full documentation, see `Boing.TeslaMiddleware`.
### Req
```elixir
iex(1)> client = Req.new() |> Boing.ReqPlugin.attach()
%Req.Request{...}
iex(2)> for _ <- 1..3, do: spawn(fn -> dbg(Req.get(client, url: "http://example.com")) end)
[#PID<0.208.0>, #PID<0.209.0>, #PID<0.210.0>]
Req.get(client, url: "http://example.com") #=> {:error, %Boing.ReqPlugin.DebouncedException{url: "http://example.com"}}
Req.get(client, url: "http://example.com") #=> {:error, %Boing.ReqPlugin.DebouncedException{url: "http://example.com"}}
Req.get(client, url: "http://example.com") #=> {:ok, %Req.Response{body: ...}}
```
For full documentation see `Boing.ReqPlugin`.
### Direct
```elixir
iex(1)> for i <- 1..3, do: spawn(fn -> IO.puts("Foo #{i}: #{inspect(Boing.debounce("foo"))}") end)
[#PID<0.221.0>, #PID<0.222.0>, #PID<0.223.0>]
iex(2)> for i <- 1..3, do: spawn(fn -> IO.puts("Bar #{i}: #{inspect(Boing.debounce("bar"))}") end)
[#PID<0.225.0>, #PID<0.226.0>, #PID<0.227.0>]
Bar 3: :ok
Foo 3: :ok
Bar 1: {:error, [debounced: "bar"]}
Foo 1: {:error, [debounced: "foo"]}
Foo 2: {:error, [debounced: "foo"]}
Bar 2: {:error, [debounced: "bar"]}
```
For full documentation see `Boing`.
## Overview
Actions are debounced by assigning a key to related actions. For the Req and Tesla modules, the
GET request URL is automatically used as the key. When the first action for that key occurs,
a 1 second (by default, but configurable) timer is started. The timer is restarted for each subsequent
request to the same key/URL that occurs before the timer expires. When the timer eventually expires,
the most recent request is permitted, and the previous requests are debounced.
While this module includes support for Tesla and Req, the core logic is implementation-independent
and can be used for any purpose.
For full documentation of the underlying implementation, see `Boing`.
## Installation
Boing can be installed by adding it to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:boing, "~> 0.1.0"}
]
end
```
## Documentation
Full documentation is available in `iex` via the [`h`](`IEx.Helpers.h/1`) helper and also is published
to [Hex](https://hexdocs.pm/boing/).