# `Snodo.Server`
[🔗](https://github.com/joshrotenberg/snodo/blob/v0.1.0/lib/snodo/server.ex#L1)

Dialect-driven direct dispatch and a declarative server builder.

`use Snodo.Server` builds `router/0`, `protocols/0`, `runtime/1`, and
`child_spec/1` from the components the module declares. A component is
either an existing module or an inline block:

    defmodule EchoServer do
      use Snodo.Server, name: "echo-server", version: "0.1.0"

      tool "greet", description: "Create a greeting" do
        argument "name", :string, required: true

        @impl true
        def call(%{"name" => name}, _context), do: {:ok, "Hello, #{name}!"}
      end

      resource "toolbox_groups", uri: "toolbox://groups", mime_type: "application/json" do
        @impl true
        def read(_params, _context), do: {:ok, %{"groups" => ["web", "data"]}}
      end

      prompt "review", description: "Review a package" do
        argument "name", required: true

        @impl true
        def render(%{"name" => name}, _context), do: {:ok, "Review #{name}."}
      end

      tool MyApp.Search
    end

An inline block is the body of a generated module that uses
`Snodo.Tool.Simple`, `Snodo.Resource.Simple`, or `Snodo.Prompt.Simple` with the
given name and options. The module is named after the component, here
`EchoServer.Tools.Greet`, `EchoServer.Resources.ToolboxGroups`, and
`EchoServer.Prompts.Review`, and is registered exactly as a module component
is. Inline and module components can be mixed freely.

# `dispatch_result`

```elixir
@type dispatch_result() :: {:ok, map() | nil} | {:stream, Snodo.Subscription.t()}
```

# `dispatch`

```elixir
@spec dispatch(Snodo.Server.Runtime.t(), term(), Snodo.Transport.Context.t()) ::
  dispatch_result()
```

Dispatches one decoded JSON-RPC map through the configured dialect and router.

# `prompt`
*macro* 

Registers an existing prompt module, one that implements `Snodo.Prompt`
directly or through `Snodo.Prompt.Simple`.

The module is registered with `Snodo.Router.register_prompt/2` each time
`router/0` or `runtime/1` runs, which raises `ArgumentError` for an invalid
module or a duplicate prompt name.

# `prompt`
*macro* 

Defines and registers an inline prompt module that uses `Snodo.Prompt.Simple`.

`opts` are the `Snodo.Prompt.Simple` options other than `:name`.

# `reject`

```elixir
@spec reject(
  Snodo.Server.Runtime.t(),
  term(),
  Snodo.Transport.Context.t(),
  Snodo.Error.t()
) ::
  dispatch_result()
```

Shapes an execution-policy error through the selected protocol dialect.

# `resource`
*macro* 

Registers an existing resource module, one that implements `Snodo.Resource`
directly or through `Snodo.Resource.Simple`.

The module is registered with `Snodo.Router.register_resource/2` each time
`router/0` or `runtime/1` runs, which raises `ArgumentError` for an invalid
module or a colliding name, URI, or URI template.

# `resource`
*macro* 

Defines and registers an inline resource module that uses
`Snodo.Resource.Simple`.

`opts` are the `Snodo.Resource` options other than `:name`, and must include
`:uri` or `:uri_template`.

# `tool`
*macro* 

Registers an existing tool module, one that implements `Snodo.Tool`
directly or through `Snodo.Tool.Simple`.

The module is registered with `Snodo.Router.register_tool/2` each time
`router/0` or `runtime/1` runs, which raises `ArgumentError` for an invalid
module or a duplicate tool name.

# `tool`
*macro* 

Defines and registers an inline tool module that uses `Snodo.Tool.Simple`.

`opts` are the `Snodo.Tool.Simple` options other than `:name`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
