A PDF should not discover business errors
Without validation, incomplete input can produce a technically valid but useless document: an invoice without a number, a contract without a party or a table without currency. The PDF renderer is not the right place to decide whether data makes sense.
Validation should happen before rendering, using a contract understood by both the calling application and the document service.
Describe the expected shape
JSON Schema can express objects, types, required fields, formats and simple constraints.
{
"type": "object",
"required": ["invoice", "customer", "items"],
"properties": {
"invoice": {
"type": "object",
"required": ["number", "date"],
"properties": {
"number": { "type": "string", "minLength": 1 },
"date": { "type": "string", "format": "date" }
}
},
"items": { "type": "array", "minItems": 1 }
}
}
The schema does not replace deeper business rules. It can verify that a total is numeric, but your billing system still owns the calculation.
Return actionable errors
A useful error identifies a path, rule and stable explanation:
{
"code": "DOCUMENT_PAYLOAD_INVALID",
"errors": [
{ "path": "invoice.number", "rule": "required", "message": "Invoice number is required" }
]
}
Do not copy the full payload into logs. Retain a request identifier, schema version and failing paths. Personal and contractual data should remain protected.
Evolve the schema safely
Not every change has the same impact. Adding an optional field is usually compatible. Adding a required field, deleting a consumed property or changing a type can break existing callers.
An automated comparison can classify changes as compatible, additive or breaking. Until that exists, record every schema change in the template review.
Keep schema and template aligned
A declared field that is never used creates noise. A binding used by the template but absent from the schema creates a blind spot. Check both directions: every binding should be declared and every required field should be justified.
Sample data should validate against the schema because it supports preview, tests and integration understanding.
Validation checklist
- Validation happens before expensive job creation.
- Errors expose stable paths.
- Logs avoid full payloads.
- The schema belongs to a template version.
- Samples are valid themselves.
- Breaking changes are identified.
- Business rules stay with their owning service.
Frequently asked questions
Validate client-side or in the API?
Both can help. Client validation improves developer feedback; the API must validate again because it cannot trust callers.
Should unknown fields be rejected?
For a strict contract, yes. During gradual migration, accepting them can ease evolution. Make the policy explicit and test it.