2.0 KiB · text 5af55d9
defmodule GitGudWeb.Plugs.Twirp do
@moduledoc """
Tiny helpers for emitting Twirp-compliant responses.
Twirp methods accept POST with `Content-Type: application/json` or
`application/protobuf`. We currently only do JSON; protobuf framing
for runner.v1 messages is a TODO — see `lib/git_gud_web/controllers/runner_controller.ex`.
"""
import Plug.Conn
@doc "Encode a successful Twirp JSON response."
def ok(conn, payload) do
conn
|> put_resp_content_type("application/json", nil)
|> send_resp(200, Jason.encode!(payload))
end
@doc """
Emit a Twirp error. `code` is one of the Twirp canonical codes
(canceled, unknown, invalid_argument, deadline_exceeded, not_found,
already_exists, permission_denied, unauthenticated, resource_exhausted,
failed_precondition, aborted, out_of_range, unimplemented, internal,
unavailable, dataloss).
"""
def error(conn, code, msg, meta \\ %{}) do
status = code_to_status(code)
body =
%{
"code" => Atom.to_string(code),
"msg" => msg,
"meta" => meta
}
|> Jason.encode!()
conn
|> put_resp_content_type("application/json", nil)
# Match the runner-protocol success path: force `Connection:
# close` so the runner opens a fresh TCP connection for its
# next request. Eliminates the HTTP/1.1 keep-alive framing-
# cascade where one mis-sized response corrupts the parse of
# the next request line.
|> put_resp_header("connection", "close")
|> send_resp(status, body)
end
defp code_to_status(:invalid_argument), do: 400
defp code_to_status(:unauthenticated), do: 401
defp code_to_status(:permission_denied), do: 403
defp code_to_status(:not_found), do: 404
defp code_to_status(:already_exists), do: 409
defp code_to_status(:failed_precondition), do: 412
defp code_to_status(:resource_exhausted), do: 429
defp code_to_status(:unimplemented), do: 501
defp code_to_status(:unavailable), do: 503
defp code_to_status(_), do: 500
end