Skip to content

Low-level definitions

Model-bound classes are the default. Keep defineCommand, defineQuery, and defineObservableQuery when you already have Zod schemas, need explicit validate and filters callbacks, or integrate code that cannot use decorators. The definitions run through the same pipelines as model-bound artifacts.

import { ArcServer, defineCommand, defineQuery } from '@cratis/arc.core';
import { z } from 'zod';
const tasks = new Map<string, string>();
const create = defineCommand({
name: 'Create', namespace: 'Tasks', schema: z.object({ id: z.string(), title: z.string() }),
handle: ({ id, title }) => { tasks.set(id, title); return id; }
});
const list = defineQuery({
name: 'List', namespace: 'Tasks', schema: z.object({}),
perform: () => [...tasks].map(([id, title]) => ({ id, title }))
});
const server = new ArcServer({ commands: [create], queries: [list] });

This registers two operations in memory. Host server with runArc or a host adapter to serve POST /api/tasks/create and GET /api/tasks/list. You can also pass the definitions to ArcApplication.createBuilder({ commands: [create], queries: [list] }) next to model-bound artifacts.

  • The Zod schema, not field decorators, controls the input and its JSON Schema. Schemas must convert to JSON Schema; see Command filters.
  • Services are declared with handlerDependencies and validatorDependencies and resolved with currentServices(); see Dependency injection.
  • Validation uses validate and filters; see Command filters.
  • Commands can declare execution scopes.
  • Authorization is a property: authorization: { roles: ['editor'] }, plus an optional per-request authorize(input, context); see Authorizing commands and queries.
  • Client generation uses an explicit clientOutput contract and the low-level manifest.

Do not mix both representations for the same operation: duplicate names or routes are rejected at startup. The full list of definition fields is in Configuration.