Skip to content

How types appear in the document

Your command declares @field(TaskId) id. A client generator in Go or Python must not see a TaskId object with a value inside it, because the JSON on the wire carries a plain UUID string. Arc builds every schema in the document from the same wire rules that bind and serialize requests, so what the document says is what the wire carries.

The same schemas appear in the introspection endpoints: a command’s payloadSchema in /.cratis/commands is identical to its OpenAPI request body schema.

This command uses concepts, enums, and each field modifier:

Features/Tasks/Planning.ts
import { field, ConceptAs, Guid } from '@cratis/fundamentals';
import { command, defaultValue, enumeration, nullable, optional } from '@cratis/arc.core';
export class TaskId extends ConceptAs<Guid> { static readonly valueType = Guid; }
export class Estimate extends ConceptAs<number> { static readonly valueType = Number; }
export enum Priority { Low, Normal, High }
export enum Status { Open = 'open', Done = 'done' }
@command({ namespace: 'Tasks' })
export class PlanTask {
@field(TaskId) id!: TaskId;
@field(Estimate) estimate!: Estimate;
@field(Number) @enumeration(Priority) priority!: Priority;
@field(String) @enumeration(Status) status!: Status;
@field(String) @optional() note?: string;
@field(Date) @nullable() due!: Date | null;
@field(Boolean) @defaultValue(false) urgent!: boolean;
handle(): void {}
}

Its request body schema in /openapi.json:

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "string", "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", "format": "uuid" },
"estimate": { "type": "number" },
"priority": { "anyOf": [{ "type": "number", "const": 0 }, { "type": "number", "const": 1 }, { "type": "number", "const": 2 }] },
"status": { "anyOf": [{ "type": "string", "const": "open" }, { "type": "string", "const": "done" }] },
"note": { "type": "string" },
"due": { "anyOf": [{ "type": "string", "format": "date-time" }, { "type": "null" }] },
"urgent": { "default": false, "type": "boolean" }
},
"required": ["id", "estimate", "priority", "status", "due"]
}

The sections below explain each property. Concepts, enums, and result types have their own pages; this page covers the field modifiers and derived types that apply to all of them.

A concept is described as the value it wraps: id is a UUID string, and estimate is a number. The name TaskId appears nowhere, because nothing on the wire carries it. Concepts in the document has the table for every declared type, and explains why concept validators do not become schema constraints.

@enumeration(Enum) lists the enum’s values, one const per member: priority is 0, 1, or 2, and status is open or done. Enums in the document covers numeric and string enums and the difference from Arc on .NET.

FieldSchemaRequired?
@field(String) notestringYes
@field(String) @optional() notestringNo; the property may be left out
@field(Date) @nullable() dueanyOf the type and nullYes; the property must be present, and may be null
@field(Boolean) @defaultValue(false) urgentboolean with default: falseNo; Arc fills in the default

In input schemas, a field whose type has registered @derivedType('id') subclasses is described with oneOf, one variant per subclass, each carrying its _derivedTypeId. See Wire format for the rules.

Command responses and query data use the same rules, with two differences: they appear only when generated artifact metadata declares the return type, and output object schemas set additionalProperties: false. See Commands in the document and Queries in the document.