Warning
AshSmithy was created agentically, modelled on other Ash extensions such as AshJsonApi and AshGraphql. It is an early experiment in compatibility with Smithy, and has not yet been used in production.
The server is tested against the official Smithy protocol compliance tests for
aws.protocols#restJson1, from software.amazon.smithy:smithy-aws-protocol-tests.
It passes 832 of the 880 test cases (request, response, error and malformed request
cases). The other 48 are skipped because they rely on traits AshSmithy never generates:
@httpPayload (44), @endpoint (2) and @requestCompression (2).
AshSmithy generates Smithy models from your Ash resources, and serves
them over Smithy protocols. Currently that is restJson1.
Describe which actions to expose, and AshSmithy builds the Smithy service, resources, operations and shapes from your resources' attributes, arguments, types and constraints. The generated model can be used with the Smithy toolchain, e.g. to validate it or to generate clients in other languages.
With Igniter:
mix igniter.install ash_smithyThis adds the dependency and formatter rules, creates a SmithyRouter for your domains, and
mounts it at /api/smithy in your Phoenix router.
Or add it to your dependencies yourself:
def deps do
[
{:ash_smithy, "~> 0.1.0"}
]
endAdd AshSmithy.Domain to a domain, to expose it as a Smithy service:
defmodule MyApp.Helpdesk do
use Ash.Domain, extensions: [AshSmithy.Domain]
smithy do
namespace "com.example.helpdesk"
version "2026-10-01"
title "Helpdesk Service"
end
resources do
resource MyApp.Helpdesk.Ticket
end
endThen add AshSmithy.Resource to its resources, and choose the operations to expose:
defmodule MyApp.Helpdesk.Ticket do
use Ash.Resource,
domain: MyApp.Helpdesk,
extensions: [AshSmithy.Resource]
smithy do
relationships([:representative])
operations do
create :open
read :read
update :update
delete :destroy, idempotent?: true
list :read
operation :close
collection_operation :search
end
end
# ...
endcreate, read, update, delete and list become the Smithy resource's lifecycle
operations. operation binds any other action to a single record, and collection_operation
binds one to the collection. List operations are paginated, and accept filters and sorts as
query parameters.
Serve the operations of one or more domains with a router:
defmodule MyAppWeb.SmithyRouter do
use AshSmithy.Router,
domains: [MyApp.Helpdesk],
model: "/model.json"
endThen forward to it, e.g. from your Phoenix router:
scope "/api/smithy" do
pipe_through [:api]
forward "/", MyAppWeb.SmithyRouter
endThe actor, tenant and context are taken from the conn, as set by Ash.PlugHelpers.
mix ash_smithy.codegenThis writes the Smithy IDL for each domain to priv/smithy/model/, along with a
smithy-build.json. Then use the Smithy CLI
to validate the model or generate clients:
cd priv/smithy && smithy buildIt also runs as part of mix ash.codegen, and mix ash.codegen --check fails if the model is
out of date. See mix help ash_smithy.codegen for options, including writing the JSON AST.
The compliance tests need the Smithy CLI
to fetch the protocol test models. Have smithy on your path, or set SMITHY_CLI, then:
mix testWithout the Smithy CLI, the compliance tests are skipped unless the protocol test models have
already been fetched to _build/smithy-protocol-tests.json.