Command proxy generation
The proxy generator creates TypeScript command classes that provide type-safe command execution with React hook integration.
Supported approaches
Section titled “Supported approaches”Commands can be implemented using two approaches, both of which are supported by the proxy generator:
- Controller-based: Commands in ASP.NET Core controllers using
[HttpPost]attributes - Model-bound: Simplified approach where a type represents the command directly
For detailed information on implementing commands, see the Commands documentation.
How commands are discovered
Section titled “How commands are discovered”Controller-based commands
Section titled “Controller-based commands”The generator discovers controller-based commands by looking for:
- Methods marked with
[HttpPost] - Parameters marked with
[FromBody],[FromRoute], or[FromQuery]
See Controller-based Commands for implementation details.
Model-bound commands
Section titled “Model-bound commands”The generator discovers model-bound commands by finding types that:
- Are decorated with the
[Command]attribute - Have a
Handle()method (the command handler)
The type name becomes the command name. Public instance properties declared directly on the command type become command properties in the generated TypeScript; this pass does not collect inherited properties.
See Model-bound Commands for implementation details.
Generated command structure
Section titled “Generated command structure”Generated command classes:
- Extend the
Commandbase class from@cratis/arc/commands - Include all properties from route parameters, query parameters, and body content
- Provide a static
use()method for React hook integration - Include the proper route based on the configuration
Generated artifacts
Section titled “Generated artifacts”For each command, the generator creates:
- Interface: An
ICommandNameinterface with all command properties - Class: A
CommandNameclass extendingCommand<ICommandName>, orCommand<ICommandName, TResponse>for a response-bearing command - Route: The HTTP route derived from the controller route or model-bound configuration
Command operations stay on the server
Section titled “Command operations stay on the server”Command operations declare inline work rather than response DTOs. The generator excludes ICommandOperation implementations and CommandOperations batches from the caller’s response, including supported tuple and result alternatives. A tuple containing a response and operations produces a response-bearing proxy for the response alone; an operation-only command has no response payload.
No operation execution or compensation code is generated for the frontend. Backend recovery observations are also excluded from HTTP JSON. Clients continue to use the existing CommandResult contract.
Operation method invokers are generated by Arc’s C# source generator. TypeScript proxies are still produced by the separate post-build proxy generator; these are different generation steps.
Excluding commands from generation
Section titled “Excluding commands from generation”To exclude specific controller-based commands from proxy generation, mark them with the [AspNetResult] attribute. This is useful when you want to handle the response manually or when the command returns a non-standard result.
Route configuration
Section titled “Route configuration”For conventional model-bound commands, the generated route is affected by the CratisProxiesSkipCommandNameInRoute configuration option. Controller routes come from their ASP.NET declarations, not this switch:
- When
false(default): The command type name is included in the route - When
true: The command type name is excluded from the route
Automatic Conflict Detection: When CratisProxiesSkipCommandNameInRoute is true, the proxy generator automatically detects if multiple commands exist in the same namespace (after skipping segments). If a conflict is detected, the command name is automatically included in the route to prevent route collisions. Align the generator’s settings with the runtime endpoint settings; changing the build configuration does not configure the server.
For example:
- Single command in namespace: Route is clean without type name (e.g.,
/api/orders) - Multiple commands in same namespace: Type names are added automatically (e.g.,
/api/orders/create-order,/api/orders/update-order)
The examples assume the application namespace prefix has been skipped. See routing configuration for segment counts, defaults, and runtime alignment.
Frontend usage
Section titled “Frontend usage”The generated command proxies integrate with React through the use() static method, which returns:
- The command instance with all properties.
- A
SetCommandValues<ICommandName>setter for editing values. - A
ClearCommandValuesfunction.
The signature is use(initialValues?: ICommandName): [CommandName, SetCommandValues<ICommandName>, ClearCommandValues]. This is an API shape, not a manually authored replacement for the generated class. The setter edits values; it does not establish a new change-tracking baseline.
Await execute() to receive a CommandResult with success/failure information, validationResults, and the typed response when applicable.
For frontend usage patterns, see React commands. Commands can return ordinary application responses, including Guid; proxy generation does not require event sourcing.