Skip to content

Validation and behavior

Core queries validate input and provide predictable execution behavior.

Validation metadata is generated from backend FluentValidation rules through the proxy generator.

const query = new SearchUsersQuery();
query.parameters = { searchTerm: 'ab', minAge: -5 };
const result = await query.perform();
// result.isValid === false
// result.validationResults contains validation errors

Observable queries validate the same way. perform() returns an invalid result, and subscribe() delivers one to your callback instead of opening a connection:

const query = new ObserveUsers();
query.subscribe(result => {
// result.isValid === false when the arguments were rejected,
// which is distinct from a valid result that simply has no data yet
}, { minAge: -5 });

Missing arguments behave differently from arguments that break a rule. When a required argument is absent and no generated client rule (such as notEmpty()) has already rejected it, subscribe() opens no connection and delivers the query’s default value as an empty result whose isSuccess and isValid are both true, so the screen cannot tell “no arguments yet” from “no data”. Gate the subscription with ObservableQueryWhen so it only starts once the arguments exist:

In a React component, use the generated wrapper (illustrative fragment):

const [books] = BooksForAuthor.when(!!authorId).use({ authorId });

ObservableQueryWhen is a class returned by .when(), not a JSX component. Supply a correctly typed argument/default even while disabled; the condition suppresses automatic subscription, not all query/cache creation. See conditional queries.

Client-side validation is a convenience, not a gate — every rule it applies is also enforced by the server, so calling an endpoint directly gains nothing. Server rejections report member names the same way the client does: camelCased, and attributed to the field rather than to a concept’s inner value.

For an HTTP query request, a server validation rejection returns HTTP 400 with a query result whose isValid and isSuccess are false and whose validationResults contain the member names and messages. perform() preserves that result, and React query hooks expose those same fields. Observable subscriptions to model-bound queries deliver one invalid result through the callback and then end that subscription, over either WebSocket or SSE, in direct or hub mode. A controller-based observable query over a direct WebSocket still fails the connection instead (#3230).

For general validation docs, see Validation.

Queries include native sorting and paging primitives via Sorting and Paging.

For React usage patterns and generated hooks, see Paging.

When a newer request supersedes an active one, Arc cancels stale work to reduce race conditions and unnecessary processing.

Typical query failure categories include:

  • Parameter validation errors
  • Network failures
  • Timeouts and cancellations
  • Server exceptions