defmodule PingPong.Service.HTTP do
@moduledoc """
Shared HTTP helper used by network-backed services.
The helper JSON-encodes request bodies, sends them with `Req`, and normalizes
HTTP and transport failures into PingPong result tuples. It is intentionally
small and service-agnostic so service modules can focus on mapping their own
payloads and options.
"""
@doc """
Sends a JSON `POST` request.
`success_status` defaults to `200`. Services such as Discord can pass a
different status, for example `204`.
## Return values
- `{:ok, response}` for the expected HTTP status
- `{:error, {:error_response, response}}` for other HTTP responses
- `{:error, {:error, reason}}` for transport errors
- `{:error, {:unknown_response, response}}` for unexpected `Req` results
"""
@spec post(binary(), map(), integer()) :: PingPong.result()
def post(url, body, success_status \\ 200) do
json_payload = JSON.encode!(body)
headers = [
{"Accept", "application/json"},
{"Content-Type", "application/json; charset=utf-8"}
]
case Req.post(url, body: json_payload, headers: headers) do
{:ok, %Req.Response{body: response, status: ^success_status}} ->
{:ok, response}
{:ok, %Req.Response{body: response}} ->
{:error, {:error_response, response}}
{:error, %Req.TransportError{reason: reason}} ->
{:error, {:error, reason}}
_ = e ->
{:error, {:unknown_response, e}}
end
end
end