Packages

A Slack Web & Real Time Messaging API client.

Current section

Files

Jump to
slack_kit lib slack web default_client.ex
Raw

lib/slack/web/default_client.ex

defmodule Slack.Web.DefaultClient do
@moduledoc """
Default `Slack.Web.Client` implementation, built on `Req`.
Every call generated under `Slack.Web.*` is delivered as an HTTP POST. Form
bodies are sent as `application/x-www-form-urlencoded`; uploads are sent as
`multipart/form-data` with the file streamed from disk.
Responses are JSON-decoded and returned **unwrapped** — i.e. the caller
receives the body map directly, so successful calls and Slack-level errors
(`%{"ok" => false, "error" => …}`) are surfaced identically. Transport
failures raise via `Req.post!/2`.
Request options can be tuned globally via the `:web_http_client_opts` config
key:
config :slack, :web_http_client_opts,
connect_options: [timeout: 10_000],
receive_timeout: 10_000
For richer behaviour — retries, response wrapping, telemetry, custom error
handling — swap in a module implementing `Slack.Web.Client`:
config :slack, :web_http_client, MyApp.SlackClient
"""
@behaviour Slack.Web.Client
@impl true
def post!(url, {:form, params}) do
url
|> Req.post!(Keyword.merge(opts(), form: params))
|> Map.fetch!(:body)
|> decode_body()
end
def post!(url, {:multipart, parts}) do
url
|> Req.post!(Keyword.merge(opts(), form_multipart: build_multipart(parts)))
|> Map.fetch!(:body)
|> decode_body()
end
defp build_multipart(parts) do
Enum.map(parts, fn
{:file, path, _} ->
{:file, {File.stream!(path), filename: Path.basename(path)}}
{"", value, {"form-data", [{"name", name}]}, _} ->
{to_field_name(name), value}
end)
end
defp to_field_name(name) when is_atom(name), do: name
defp to_field_name(name) when is_binary(name), do: String.to_atom(name)
defp decode_body(body) when is_binary(body), do: JSON.decode!(body)
defp decode_body(body), do: body
defp opts do
Application.get_env(:slack, :web_http_client_opts, [])
end
end