Guide

Schema and code

Check templates and data against a JSON Schema before each render, and write the first template from your classes.

On this page

Community

The schema file

A template can have a JSON Schema next to it, with the same name:

rechnung.md
rechnung.schema.json

When the file exists, every brevier pdf and brevier html checks two things before it prints:

  1. Each {{ }} tag in the template names a field that the schema has.
  2. The data matches the schema: required fields, types, lists.

If one check fails, nothing is printed. Brevier lists every problem, with the template line for the first check.

When there is no schema file, Brevier skips both checks.

--schema chooses another schema: the path of a file, or false to skip the checks.

rechnung.schema.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "rechnung": {
      "type": "object",
      "properties": {
        "nummer": { "type": "string", "title": "Rechnungsnummer" },
        "summe": { "type": "number", "format": "decimal" }
      },
      "required": ["nummer", "summe"]
    }
  },
  "required": ["rechnung"]
}

A column's title in the schema is also the default header text of a table block.

From your classes

You do not have to write the schema by hand. It comes from the classes you already pass to your old PDF library, in two steps. Your classes need no Brevier interface, base class or annotation.

1. Write the schema

In Java, a build step reads your compiled classes. brevier-codegen.jar is built by the Java client.

java -cp build/classes:brevier-codegen.jar dev.brevier.codegen.SchemaGeneratorCommand \
  --root rechnung=com.ww.Rechnung --root kunde=com.ww.Kunde > rechnung.schema.json

Each --root is one top-level field of the data: name=class. Add [] after the class for a list: --root positionen=com.ww.Position[].

In Python, brevier.schema() reads dataclasses, pydantic v2 models, attrs classes, TypedDicts, Django models and SQLAlchemy models:

write_schema.py
import json
from pathlib import Path

import brevier
from billing.models import Kunde, Rechnung

schema = brevier.schema(Rechnung, kunde=Kunde)
Path("rechnung.schema.json").write_text(json.dumps(schema, indent=2), encoding="utf-8")

A class passed without a name gets the class name with a small first letter: Rechnung becomes rechnung.

In C#, BrevierSchema.Create() reads your classes:

WriteSchema.cs
using System.IO;
using System.Text.Json;
using Brevier;

var schema = BrevierSchema.Create(typeof(Rechnung), typeof(Kunde));
File.WriteAllText("rechnung.schema.json", schema.ToJsonString(new() { WriteIndented = true }));

2. Write the template

brevier template --schema rechnung.schema.json

This writes three files next to the schema:

File Content
rechnung.html A first template that uses every field.
rechnung.css A stylesheet to start from.
sample.json Sample data that matches the schema.

--format md writes a Markdown template instead of HTML. brevier template never overwrites a file. If one of the three files exists, it writes none of them. Add --force to replace them all.

From one record

If you have a real record and no classes, scaffold writes all four files from it: the schema, the template, the stylesheet and the sample data.

brevier scaffold --from rechnung.json

From a template

If you have the template, from-template writes the schema it needs. With --lang java17 it also writes Java classes for the data.

brevier from-template rechnung.html

See Command line for all options.

The TypeScript client does not read types yet. Use brevier scaffold --from rechnung.json or write the schema by hand.