Skip to content

Simple example

Start with TypeSpec models that represent the runtime shape you want every target to agree on. Use Typra samples as evidence for generated examples and conformance tests; samples are not runtime defaults.

import "@typra/emitter";
import "@typespec/http";
using TypeSpec.Http;
namespace Todo.Contracts;
model TodoList {
name: string;
items: TodoItem[];
}
model TodoItem {
@sample(#{ id: "todo-1" })
id: string;
@sample(#{ title: "Write the contract" })
title: string;
state: TodoState;
}
union TodoState {
open: "open";
done: "done";
archived: "archived";
}

Add callable contracts with TypeSpec-native interface and op declarations. Attach @vector cases when behavior should be verified across generated runtimes.

model RenderRequest {
item: TodoItem;
}
model RenderResult {
text: string;
}
const RenderVectors = #[
#{
name: "open-item",
stage: "render",
input: #{ request: #{ item: #{ id: "todo-1", title: "Write the contract", state: "open" } } },
expected: #{ text: "- [ ] Write the contract" }
}
];
interface TodoRenderer {
@vector(RenderVectors)
render(request: RenderRequest): RenderResult;
}

When you need transport projection, layer official TypeSpec HTTP decorators on the callable operation. Typra consumes that HTTP metadata; it does not invent a parallel routing vocabulary.

@route("/todos")
interface TodoApi {
@get
@route("/{id}")
read(@path id: string): TodoItem;
}

Configure Typra with the root model and the targets you want to emit:

emit:
- "@typra/emitter"
options:
"@typra/emitter":
emitter-output-dir: "{cwd}/generated"
root-object: "Todo.Contracts.TodoList"
deterministic-output: true
emit-targets:
- type: TypeScript
output-dir: "generated/typescript"
test-dir: "generated/typescript/tests"
import-path: "../index"
- type: Python
output-dir: "generated/python/todo_contracts"
test-dir: "generated/python/tests"
import-path: "todo_contracts"
outputs:
- kind: server
provider: fastapi
- type: Markdown
output-dir: "generated/markdown"

Compile with TypeSpec:

Terminal window
npx tsp compile ./main.tsp --config ./tspconfig.yaml

Typra emits target code, generated tests when test-dir is set, Markdown reference output when requested, optional contributor outputs such as FastAPI route scaffolds, and metadata that can be compared in CI.

generated\
typescript\
python\
todo_contracts\
fastapi_routes.py
markdown\
json-ast\model.json
.typra-generated\manifest.json
.typra-generated\report.json

The important split is ownership: TypeSpec owns the durable contract, Typra owns repeatable generated surfaces, and your product owns any runtime behavior around those surfaces.