Skip to content

Commands

Arc wraps participating controller commands in a CommandResult or CommandResult<T> envelope. This is not a guarantee about every arbitrary mutation endpoint in an ASP.NET application. The CommandResultOperationTransformer automatically updates the generated operation documentation to reflect this.

For every endpoint whose controller action or method is identified as a command (not marked with [AspNetResult]), the transformer:

  1. Replaces the 200 response schema with CommandResult (for void/Task returns) or CommandResult<T> (for typed returns).
  2. Adds standard error response schemas for 400, 403, and 500 status codes — all using the same CommandResult/CommandResult<T> schema so clients only need to handle one type.
Status codeMeaning
200Command executed successfully
400Validation error or malformed payload
403Forbidden — insufficient permissions
500Unexpected server error

If the command returns a concept (a type inheriting from ConceptAs<T>), the transformer unwraps the concept to its underlying primitive type before generating the CommandResult<T> schema.

The following type/action fragments illustrate a response contract; place the action inside an existing MVC controller and supply the application service:

public record InvoiceId(Guid Value) : Cratis.Concepts.ConceptAs<Guid>(Value);
[HttpPost]
public Task<InvoiceId> CreateInvoice(CreateInvoice command, [FromServices] IInvoiceService invoices) =>
invoices.Create(command);

The transformer constructs CommandResult<Guid>; its response member is represented in JSON Schema as a string with UUID format. It does not change a runtime Guid response into a different command contract.

Decorate the action with [AspNetResult] to bypass the transformer and expose the raw return type directly:

[HttpPost]
[AspNetResult]
public Task<InvoiceId> CreateInvoice(CreateInvoice command, [FromServices] IInvoiceService invoices) =>
invoices.Create(command);