What this is about
A render request tells CRMS which document you want: from which template, in which format, with which data. CRMS answers in the same call with the finished document.
You can ask CRMS in two ways. Embedded, CRMS runs inside your application, and you call a Java interface. Standalone, CRMS runs as a separate service, and you send the request over HTTP. The content of the request is the same in both cases. How the two operating modes come about is described in Embedded or standalone.
A request, field by field
POST /crms/render
Content-Type: application/json
Authorization: Bearer <token>
{
"template": "audit-report", ← template key, required
"format": "PDF", ← format, required
"mode": "FINAL", ← PREVIEW, FINAL or TRANSIENT, required
"reference": "audit-4711", ← your reference, required for FINAL
"locale": "de-DE", ← language, optional
"timeZone": "Europe/Berlin", ← time zone, optional
"pdfProfile": "PDF_A_3A", ← only for PDF, optional
"data": { ← the payload
"customer": { "name": "ACME" }
},
"attachments": [] ← pictures of this request, optional
}HTTP 200
Content-Type: application/pdf
Content-Disposition: inline; filename="audit-report.pdf"
Crms-Template-Key: audit-report
Crms-Template-Scope: TENANT
Crms-Template-Variant: de
Crms-Template-Revision: 3f0c…
Crms-Template-Revision-Hash: sha-256:9a1e…
Crms-Document-Revision: 7b42… ← only for FINAL
X-Content-Type-Options: nosniff
%PDF-1.7 …| Field | Meaning | Required | If it is missing |
|---|---|---|---|
template | the template key: the fixed name of a template, kebab-case, for example audit-report, at most 128 characters | yes | required |
format | the output format: HTML, PDF, DOCX, XLSX, CSV, ODS. Case does not matter | yes | required |
mode | PREVIEW, FINAL or TRANSIENT, see Preview, final, transient. Case does not matter | yes | required |
reference | the reference: your own name for the thing the document belongs to, for example the id of an audit. CRMS does not read it, it stores final documents under it. 1 to 255 characters, no blanks at the edges and no control characters | only for FINAL | required for FINAL |
locale | the language as a language tag, for example de or de-CH | no | CRMS uses the caller’s language, see Language and time zone |
timeZone | the time zone, for example Europe/Berlin | no | the container’s time zone (TZ), otherwise UTC |
pdfProfile | NONE, PDF_A_3A, PDF_UA or PDF_A_3A_UA, only with format: PDF | no | the installation’s default profile, see Output types and formats |
data | the payload: the data the template inserts. A JSON object | no | empty payload |
attachments | pictures that belong to this request only, see Pictures and SVG | no | no attachments |
The response headers tell you exactly what the document was made from: which template, from which scope (the level on which the template applies: system, tenant or user), which language variant, which revision (an approved, unchangeable version of the template) and its hash. How CRMS finds the template is described in How CRMS finds the template.
How CRMS reads the request
Over REST, CRMS reads the JSON body field by field. Strict rules apply:
- Unknown fields are refused (
not-allowed). A misspelt name likerefrenceshows up at once instead of silently doing nothing. - The wrong JSON type is
invalid. CRMS converts nothing:42is not a template key. nullcounts like a missing field.- Decimal numbers in
dataare read as exact decimals, not as floating-point numbers. An amount keeps exactly its digits. pdfProfilewith a format other than PDF isnot-allowed.- All broken fields come in one answer: 422
validation-failedwithviolations.
The body is bounded before it is read. The limit follows from the payload limit, the attachment limit and some room for the other fields. If it is larger, CRMS answers 422 payload-rejected with the violation payload-too-large. The body may come compressed with Content-Encoding: gzip. The limit then applies to the unpacked bytes. Other encodings are 415 content-encoding-unsupported.
The stations before rendering
Before CRMS renders, it checks the request in this order. Each station can end the request.
-
CRMSFormatDoes the installation offer the format, and is a formatter for it installed?↳ no 422
format-not-offered|<format> -
CRMSModeIs FINAL or TRANSIENT switched on in this installation?↳ no 409
document-revisions-disabledortransient-documents-disabled -
CRMSAttachmentsIf there are attachments, is it not FINAL, and can the format draw them?↳ no 422
attachments-not-for-finalorattachments-not-for-format|<format> -
CIASCallerIs the caller signed in?↳ no 401
crms-authentication-required -
CRMSTemplateIs there a template with this key that the caller reaches?↳ no 404
template-not-found -
CRMSScope for TRANSIENTFor TRANSIENT, does the revision come from the SYSTEM scope?↳ no 422
transient-requires-system-template -
CRMSOutput typeDoes the format fit the template's output type?↳ no 422
format-not-for-template|<format>|<output type> -
CRMSPayload and attachmentsDoes the payload keep the rules, and are the attachments fine?↳ no 422
payload-rejectedwith all violations - CRMS renders and returns the document
Only after the last station does the real work start: run the template, produce the format, and for FINAL seal and store. What can go wrong there is described in Execution and limits. All errors come back in one shape, see Errors and message keys.
The ways to send a request
When: CRMS runs inside your application
You get ReportRenderPort injected and call render(request). There are short forms for the three modes: RenderRequest.preview(key, format, data), RenderRequest.transientDocument(key, format, data) and RenderRequest.finalDocument(key, format, reference, data). Language, time zone and PDF profile are left to CRMS. You get a RenderedDocument with format, bytes, origin and, for FINAL, the document revision. Errors come as CrmsException with a message key, a rejected payload as PayloadRejectedException with the violations.
Result: the document as bytes in the same call
When: CRMS runs as a separate service, or a frontend calls CRMS directly
POST /crms/render with the JSON above and a token. The answer is the document's bytes with Content-Type and the Crms-Template-* headers. An application usually calls CRMS through crms-client, which offers the same interface as embedded, see crms-client.
Result: the document as HTTP response
When: you want to know whether a request would render, without producing a document
POST /crms/render/validate with the same body, embedded validate(request). CRMS goes through all stations and runs the template once as a dry run, but produces no format. The answer is {"violations": [...]}. Empty means: would render. Payload violations and errors in the template (in field template) are in the list. If another station fails, for example the format, the error comes as it does when rendering.
Result: list of violations, empty or not
When: embedded, for very large documents
renderTo(request, outputStream) writes the bytes straight into your stream and only returns format, size and origin. For FINAL, CRMS still buffers the whole document, because it is stored first and only then goes to you.
Result: bytes in the stream, description as return value
An embedded call from the hub looks like this. It renders a transient copy without a reference and without its own time zone:
RenderedDocument document = renderer.render(new RenderRequest(
new TemplateKey("arc42"), // template key
Locale.forLanguageTag("de"), // language, or null
null, // time zone: TZ, then UTC
OutputFormat.PDF,
null, // PDF profile: the installation's default
RenderMode.TRANSIENT,
null, // reference: only for FINAL
data));
What an installation offers
GET /crms/capabilities tells you what you can request: the offered formats, the default PDF profile, the admitted scopes, the installation’s languages, whether final documents are stored (documentRevisions), whether transient ones are allowed (transientDocuments) and the limits. Embedded, CapabilitiesPort returns the same. The values come from the configuration and do not change while running.
GET /crms/capabilities{
"formats": ["HTML", "PDF", "DOCX"],
"defaultPdfProfile": "PDF_A_3A",
"scopes": ["TENANT", "SYSTEM"],
"locales": ["de", "en"],
"documentRevisions": true,
"transientDocuments": false,
"limits": {
"timeout": "PT30S",
"maxOutputBytes": 52428800,
"maxPayloadBytes": 5242880,
"maxAttachmentCount": 200,
"maxAttachmentBytes": 52428800
}
}