defmodule JSONRPC2.Spec.Request do @moduledoc """ Struct which represents JSONRPC request. """ alias JSONRPC2.Spec @type t :: %__MODULE__{ id: Spec.id(), method: Spec.method(), params: Spec.params(), jsonrpc: String.t() } @derive JSON.Encoder defstruct [:id, :method, :params, jsonrpc: "2.0"] defguard is_id(value) when is_integer(value) or is_binary(value) or is_nil(value) defguard is_params(value) when is_map(value) or is_list(value) @doc """ Build a request struct from input data Example: iex> Request.parse(%{"id" => 123, "method" => "add", "params" => %{"x" => 15, "y" => 51}, "jsonrpc" => "2.0"}) {:ok, %Request{id: 123, method: "add", params: %{"x" => 15, "y" => 51}, jsonrpc: "2.0"}} iex> Request.parse(%{"id" => nil, "method" => "add", "params" => %{"x" => 15, "y" => 51}, "jsonrpc" => "2.0"}) {:ok, %Request{id: nil, method: "add", params: %{"x" => 15, "y" => 51}, jsonrpc: "2.0"}} iex> Request.parse(%{"id" => 123, "method" => "add", "params" => %{"x" => 15, "y" => 51}}) {:invalid, 123} iex> Request.parse(%{"method" => "add", "params" => %{"x" => 15, "y" => 51}, "jsonrpc" => "2.0"}) {:invalid, nil} """ def parse(%{"id" => id, "method" => method, "params" => params, "jsonrpc" => "2.0"}) do init(method, params, id) end def parse(%{"id" => id}) do {:invalid, id} end def parse(_) do {:invalid, nil} end @doc """ Validate a request struct """ @spec valid?(t()) :: :ok | :invalid def valid?(%__MODULE__{id: _, method: method, params: params}) do if(is_binary(method) && is_params(params), do: :ok, else: :invalid) end @doc """ Instantiate a request struct """ @spec new(Spec.method(), Spec.params(), Spec.id()) :: t() def new(method, params, id) do %__MODULE__{id: id, method: method, params: params} end defp init(method, params, id) when is_binary(method) and is_params(params) and is_id(id) do {:ok, new(method, params, id)} end defp init(_method, _params, id) do {:invalid, id} end end