Snodo.Resource behaviour (snodo v0.2.0)

Copy Markdown View Source

Behaviour and compile-time convenience DSL for MCP resources.

A resource module declares either one exact :uri or one :uri_template. URI routing stays application-owned: the framework does not implement RFC 6570 expansion or authorization policy.

A template inside the simple-expansion subset described in Snodo.Resource.Template gets a generated matches?/1, so the common scheme://{var}/literal shape needs no matcher at all. A template outside that subset matches nothing until the module implements matches?/1 itself.

matches?/1 may answer in two ways. true and false route without saying anything more. {:ok, variables}, a map of string keys to string values, routes and hands the extracted template variables to read/2, so a matcher never has to be paired with a second parse of the same URI. The generated matcher uses this form. Variables may not shadow "uri" or "_meta", which the request itself owns.

read/2 receives the request params, merged with any variables the matcher bound, plus the immutable request context. It returns Snodo.Result.resource_read/2 containing text or blob content maps.

defmodule PackageInfo do
  use Snodo.Resource, uri_template: "hex://{name}/info", name: "package_info"

  @impl true
  def read(%{"name" => name}, _context), do: fetch(name)
end

Content maps must contain only JSON values, which means string keys. Snodo.JSONValue.encodable!/1 converts an atom-keyed domain value into one.

Summary

Functions

Builds one base64-encoded binary resource-content map.

Returns and validates the protocol-neutral definition for a resource module.

Builds one JSON text resource-content map.

Builds one text resource-content map.

Validates all resource callbacks and static metadata.

Callbacks

complete(t, t)

(optional)
@callback complete(Snodo.Completion.t(), Snodo.Context.t()) ::
  {:ok, Snodo.Result.t()} | {:error, Snodo.Error.t() | term()}

definition()

@callback definition() :: Snodo.Resource.Definition.t()

matches?(uri)

@callback matches?(uri :: String.t()) ::
  boolean() | {:ok, Snodo.Resource.Template.variables()}

read(params, t)

@callback read(params :: map(), Snodo.Context.t()) ::
  {:ok, Snodo.Result.t()} | {:error, Snodo.Error.t() | term()}

Functions

blob(uri, encoded, opts \\ [])

@spec blob(String.t(), String.t(), keyword()) :: map()

Builds one base64-encoded binary resource-content map.

definition(resource)

@spec definition(module()) :: Snodo.Resource.Definition.t()

Returns and validates the protocol-neutral definition for a resource module.

json(uri, value, opts \\ [])

@spec json(String.t(), term(), keyword()) :: map()

Builds one JSON text resource-content map.

text(uri, text, opts \\ [])

@spec text(String.t(), String.t(), keyword()) :: map()

Builds one text resource-content map.

validate_module!(resource)

@spec validate_module!(module()) :: :ok

Validates all resource callbacks and static metadata.