Skip to content

Model-bound and low-level operations

Arc has two ways to declare an operation: model-bound classes with decorators, and low-level defineCommand, defineQuery, and defineObservableQuery definitions. Both appear in the same document through the same code, so there is no separate registration and no operation that falls through the cracks. What differs is where Arc gets each piece of information.

Part of the operationModel-bound command or queryLow-level definition
RouteEndpoint mapping from namespace and nameThe same, or the definition’s path
operationIdNamespace.Command, or Namespace.ReadModel.method for a queryNamespace.Name
summaryJSDoc on the command class or query method, through generated metadataThe definition’s summary field
Input schema@field declarations and query arguments, through the wire rulesz.toJSONSchema of the definition’s Zod schema
response or dataThe declared return type, through generated metadataNot described
SecurityAuthorization decorators and registered bearer handlersThe authorization property and registered bearer handlers

In the Tasks sample, the RegisterTask command is Tasks.Registration.RegisterTask, and the allTasks query on the TaskItem read model is Tasks.Listing.TaskItem.allTasks. The low-level create command in Low-level definitions is Tasks.Create.

Arc reads your source only through the metadata it has at runtime. JSDoc comments and TypeScript return types are gone after compilation, so two parts of a model-bound operation need generated artifact metadata registered with builder.useGeneratedMetadata(metadata):

  • Summaries. Without metadata, summary is an empty string.
  • Result types. Without metadata, the 200 envelope has no response or data property, and every query gets the paging parameters, because Arc cannot tell a single result from a list.

A low-level definition sets summary itself. Arc does not infer its result type from the handler, so its 200 envelope has no response or data, and a low-level query always lists the paging parameters.

A low-level definition’s schema is converted with Zod’s own JSON Schema conversion, so it follows Zod’s rules rather than Arc’s wire rules:

  • An object schema sets additionalProperties: false.
  • In a command’s request body, a .optional() field is not required, but a .default(...) field is listed as required and carries its default.
  • For a query’s parameters, Arc marks an argument required only when it rejects undefined, so .optional() and .default(...) arguments are both optional.

Keep low-level schemas convertible to JSON Schema; see Command filters.