Installation & Setup Guide
View SourceThis guide provides detailed instructions for installing and configuring AshRpc in your Phoenix application.
⚠️ EXPERIMENTAL WARNING: AshRpc is still in early development and considered highly experimental. Breaking changes may occur frequently without notice. We strongly advise against using this package in production environments until it reaches a stable release (v1.0.0+).
Prerequisites
Before installing AshRpc, ensure you have:
- Elixir 1.15+
- Phoenix 1.7+
- Ash Framework 3.0+ (already configured in your application)
- PostgreSQL or another supported database
Installation Options
Option 1: Automated Installation (Recommended)
The easiest way to get started is using the automated installer:
# Add ash_rpc to your dependencies using Igniter (if installed)
mix igniter.install ash_rpc
# Or manually add to your mix.exs:
# {:ash_rpc, "~> 0.1"}
# Install dependencies
mix deps.get
# Run the installer
mix ash_rpc.install
The installer will:
- ✅ Generate
MyAppWeb.TrpcRoutermodule - ✅ Add tRPC pipeline to your Phoenix router
- ✅ Configure route forwarding to
/trpc - ✅ Format generated files
Option 2: Manual Installation
For more control over the installation process:
Step 1: Add Dependencies
Add AshRpc to your mix.exs:
defp deps do
[
...,
{:ash_rpc, "~> 0.1"},
]
endStep 2: Install Dependencies
mix deps.get
Step 3: Create tRPC Router
Create a new file lib/my_app_web/trpc_router.ex:
defmodule MyAppWeb.TrpcRouter do
use AshRpc.Router,
domains: [MyApp.Accounts, MyApp.Billing],
# Optional: Custom transformer for input/output processing
transformer: AshRpc.Output.Transformer.Identity,
# Optional: Before hooks
before: [],
# Optional: After hooks
after: [],
# Optional: Context creation function
create_context: &AshRpc.Web.Controller.default_context/1
endStep 4: Configure Phoenix Router
Add the tRPC pipeline and routes to your lib/my_app_web/router.ex:
defmodule MyAppWeb.Router do
use MyAppWeb, :router
# ... existing pipelines
# tRPC pipeline - JSON only
pipeline :ash_rpc do
plug :accepts, ["json"]
# Add authentication plugs here if needed
# plug :retrieve_from_bearer
# plug :set_actor, :user
end
# ... existing routes
# Mount tRPC under the :trpc pipeline
scope "/trpc" do
pipe_through :ash_rpc
forward "/", MyAppWeb.TrpcRouter
end
endConfiguration Options
Router Options
defmodule MyAppWeb.TrpcRouter do
use AshRpc.Router,
# Required: Domains to expose
domains: [MyApp.Accounts, MyApp.Billing, MyApp.Notifications],
# Optional: Custom input/output transformer
transformer: MyApp.TrpcTransformer,
# Optional: Before request hooks
before: [MyApp.TrpcHooks.Logging, MyApp.TrpcHooks.Metrics],
# Optional: After request hooks
after: [MyApp.TrpcHooks.Audit],
# Optional: Custom context creation function
create_context: &MyApp.TrpcContext.create/1,
# Optional: Custom middlewares
middlewares: [MyApp.TrpcMiddleware.Auth, MyApp.TrpcMiddleware.Cache]
endCustom Hooks
Create custom hooks for request processing:
# lib/my_app/trpc_hooks/logging.ex
defmodule MyApp.TrpcHooks.Logging do
@behaviour AshRpc.Execution.Middleware
@impl true
def before_request(ctx) do
Logger.info("tRPC request: #{ctx.procedure}")
ctx
end
@impl true
def after_request(ctx, result) do
Logger.info("tRPC response: #{ctx.procedure} - #{result.status}")
result
end
endCustom Context
Create custom context for requests:
# lib/my_app/trpc_context.ex
defmodule MyApp.TrpcContext do
def create(%Plug.Conn{} = conn) do
%{
actor: conn.assigns[:current_user],
tenant: conn.assigns[:current_tenant],
request_id: Logger.metadata()[:request_id],
user_agent: get_user_agent(conn),
ip_address: get_ip_address(conn)
}
end
defp get_user_agent(conn) do
conn
|> Plug.Conn.get_req_header("user-agent")
|> List.first()
end
defp get_ip_address(conn) do
conn.remote_ip
|> :inet.ntoa()
|> to_string()
end
endResource Configuration
Basic Resource Setup
Configure your Ash resources to expose actions via tRPC:
defmodule MyApp.Accounts.User do
use Ash.Resource,
extensions: [AshRpc],
domain: MyApp.Accounts
# ... resource attributes, actions, etc.
ash_rpc do
# Optional: Expose actions (only needed if not using query/mutation entities below)
# expose [:read, :create, :update, :destroy]
# Configure specific procedures with advanced features
query :read do
filterable true
sortable true
selectable true
paginatable true
end
mutation :create
mutation :update
mutation :destroy
# Custom resource name (defaults to module name)
resource_name "user"
# Configure method overrides
methods: [read: :query, create: :mutation]
end
endAdvanced Query Configuration
ash_rpc do
expose [:read, :create, :search]
# Configure read queries
query :read do
filterable true # Allow client-side filtering
sortable true # Allow client-side sorting
selectable true # Allow client-side field selection
paginatable true # Allow client-side pagination
relationships [:posts, :comments, :profile]
end
# Custom query for specific use case
query :search, :read do
filterable true
selectable false # Disable field selection for search
relationships [] # No relationships for search
end
# Configure mutations
mutation :create, :create do
metadata fn _subject, user, _ctx ->
%{user_id: user.id, created_at: user.inserted_at}
end
end
mutation :register, :register_with_password do
metadata fn _subject, user, _ctx ->
%{token: user.__metadata__.token, user_id: user.id}
end
end
endTesting the Installation
1. Verify Router Setup
Start your Phoenix server:
mix phx.server
2. Test Health Check
Make a simple HTTP request to verify the router is working:
curl -X POST http://localhost:4000/trpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"query","params":{}}'
You should receive a tRPC-compatible response.
3. Configure Resources
Add tRPC configuration to at least one resource:
defmodule MyApp.Accounts.User do
use Ash.Resource, extensions: [AshRpc]
ash_rpc do
expose [:read]
end
# ... rest of resource
end4. Test Resource Endpoint
curl -X POST http://localhost:4000/trpc/accounts.user.read \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"query","params":{}}'
Troubleshooting
Common Issues
1. Router Not Found Error
Error: UndefinedFunctionError: function MyAppWeb.TrpcRouter.init/1 is undefined
Solution: Ensure the router module is properly defined and compiled:
mix compile
mix phx.server
2. Domain Not Found Error
Error: Ash.Error.Invalid: Domain MyApp.Accounts not found
Solution: Verify the domain is correctly configured in your router:
# Check domain exists
MyApp.Accounts
# Verify router configuration
defmodule MyAppWeb.TrpcRouter do
use AshRpc.Router, domains: [MyApp.Accounts] # Correct module name
end3. Resource Not Exposed Error
Error: AshRpc.Error: Resource MyApp.Accounts.User not exposed
Solution: Add tRPC configuration to your resource:
defmodule MyApp.Accounts.User do
use Ash.Resource, extensions: [AshRpc]
ash_rpc do
expose [:read] # Add this block
end
end4. Authentication Issues
Error: Ash.Error.Forbidden: Access denied
Solution: Configure authentication in your router pipeline:
pipeline :ash_rpc do
plug :accepts, ["json"]
plug :retrieve_from_bearer # Add this
plug :set_actor, :user # Add this
endDebug Mode
Enable detailed logging for troubleshooting:
# config/dev.exs
config :logger, level: :debug
config :ash_rpc, debug: trueNext Steps
Once installation is complete:
Generate TypeScript Types:
mix ash_rpc.codegen --output=./frontend/generated --zodSet Up Authentication (see Authentication Guide)
Support
If you encounter issues during installation:
- Check the troubleshooting section above
- Open an issue on GitHub
- Join the discussion on GitHub Discussions