CrowdControl.ReqAdapter (crowd_control v0.2.0)

Copy Markdown View Source

The one Req adapter in this codebase, and the carrier for the :req_adapter test seam.

Req 0.7 deprecated setting :adapter to a function: Req.Request.adapter/1 now IO.warns on every request whose adapter is not a module. The seam this library exposes to tests (:req_adapter in a backend config, :adapter in CrowdControl.Provider.Endpoint's req_options) is necessarily a function — a stub closes over the test's own pid, options and recorder, which no module name can — so the function is carried in a registered option instead and this module is the adapter that invokes it.

Every module that hands options to Req goes through new/1, which is what makes "no function ever reaches Req's :adapter" a property of one file rather than of every call site.

iex> stub = fn request -> {request, Req.Response.new(status: 200)} end
iex> CrowdControl.ReqAdapter.new(adapter: stub).adapter
CrowdControl.ReqAdapter

A module adapter needs no indirection and is passed straight through, so Req's own adapters (and a test's, if it has one) still work.

Summary

Types

t()

The seam: a Req adapter function, an adapter module, or nothing.

Functions

Build a %Req.Request{} from options, moving a function :adapter behind this module.

Install adapter on an already-built request.

adapter as Req options, for a config or endpoint that carries them.

The Req adapter callback: invoke the carried function.

Types

t()

@type t() ::
  (Req.Request.t() -> {Req.Request.t(), Req.Response.t() | Exception.t()})
  | module()
  | nil

The seam: a Req adapter function, an adapter module, or nothing.

Functions

new(options)

@spec new(keyword()) :: Req.Request.t()

Build a %Req.Request{} from options, moving a function :adapter behind this module.

Replaces Req.request(options)'s implicit Req.new/1: pass the result to Req.request/1.

put(request, module)

@spec put(Req.Request.t(), t()) :: Req.Request.t()

Install adapter on an already-built request.

For the callers that cannot use new/1 because something else builds the request — Req.new/1 followed by a plugin's attach/2.

req_options(adapter)

@spec req_options(t()) :: keyword()

adapter as Req options, for a config or endpoint that carries them.

[] for nil, so a caller has nothing to branch on. The function is left as a plain :adapter here rather than translated: these options are data on their way to new/1, which is the only thing that hands them to Req.

run(request)

The Req adapter callback: invoke the carried function.

Returns whatever it returns — {request, response} or {request, exception}, which is the contract Req enforces on any adapter.