Managing Templates
Every ReportingCloud account has a template storage, a private store on the service for the templates your application merges again and again. A merge request then names a stored template instead of carrying it. The templates endpoints of the Web API upload, list, inspect, download and delete these templates from code, so that a deployment script or an admin page of your application keeps the storage up to date. The portal does the same by hand, as Template Storage shows.
How the Template Storage Works
A stored template is known by its file name, such as sample_invoice.tx, the demo template that every trial account starts with. The endpoints that work with a stored template take this name in the query parameter templateName: POST /v1/document/merge merges it with data, POST /v1/document/findandreplace replaces text in it, GET /v1/templates/thumbnails renders its pages and GET /v1/document/share shares it.
- Formats. The storage takes templates in the formats DOC, DOCX, RTF and TX, the TX Text Control format.
- Unique names. Template names are not case-sensitive: Invoice.docx and invoice.DOCX name the same template. An upload under a name that already exists, in any case, replaces the stored template, which keeps its stored name. Check the name with
GET /v1/templates/existsfirst when you want to keep the stored one. - Storage quota. An upload under a new name adds 1 to the template storage quota of your account, an upload that replaces a stored template doesn't, and deleting a template takes 1 off again. The plans hold from 10 templates (Basic) to 500 (Extreme), as Plans and Licensing lists.
- Stored or sent with the request. A merge can also carry the template in its request body, where it is used once and not stored. A stored template is merged faster when you use it many times, because it is not transferred with every request. The Overview of the Mail Merge section compares the two ways.
The endpoints of the storage:
| Endpoint | Method | What it does | Success response |
|---|---|---|---|
| templates/upload | POST | Stores the template of the body under templateName | 201 Created |
| templates/list | GET | Lists the stored templates | 200, an array of objects with templateName, modified and size |
| templates/count | GET | Counts the stored templates | 200, a number |
| templates/exists | GET | Checks whether a template of this name is stored | 200, true or false |
| templates/info | GET | Reads the merge fields, merge blocks and user-defined document properties | 200, a TemplateInfo object |
| templates/pagecount | GET | Counts the pages of a template | 200, a number |
| templates/download | GET | Returns the template | 200, the template as a Base64 string in a JSON string |
| templates/delete | DELETE | Deletes the template | 204 No Content |
A name that is not in the storage gets 400 Bad Request from info, pagecount, download and delete, while exists answers false. An upload is refused with 400 when the extension of the name is not .doc, .docx, .rtf or .tx, or the template has a wrong format, isn't in the format of its extension or is corrupted. It is refused with 403 Forbidden when the storage of your plan is full, and the same 403 comes for a name of more than 207 characters or with # or /. An upload whose body is not a JSON string of valid Base64 data gets 500 Internal Server Error. Errors and Status Codes lists every cause.
Every request carries an Authorization header, as Authentication describes. The samples below read the API key from the environment variable REPORTINGCLOUD_API_KEY.
Upload a Template
The body of an upload is the template as a Base64 string in a JSON string, and templateName gives the name it gets in the storage. The following commands store the local file invoice.docx as invoice.docx:
# Wrap the Base64 string of the template in a JSON string
base64 0 invoice.docx | jq . > template.json
curl POST "https://api.reporting.cloud/v1/templates/upload?templateName=invoice.docx" \
"Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"Content-Type: application/json" \
@template.json
The commands work as follows:
base64 -w 0encodes the file without line breaks, andjq -Rs .turns the encoded text into a JSON string with quotes. The body is this string alone, not an object around it.--data-binary @template.jsonsends the file unchanged, which keeps large templates out of the command line.- The answer
201 Createdmeans the template is stored. A template stored under the same name before is replaced.
List and Count the Stored Templates
GET /v1/templates/list returns one object per stored template:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/list"
[
{
"templateName": "invoice.docx",
"modified": "2016-06-02T09:25:22+00:00",
"size": 3246
},
{
"templateName": "sample_invoice.tx",
"modified": "2019-06-28T07:22:34+00:00",
"size": 35271
}
]
modified is the time of the last change in UTC, and size the size of the template in bytes. When you need the number only, GET /v1/templates/count returns it as a plain number, such as 2.
How many templates your plan still takes is in the account settings: GET /v1/account/settings returns uploadedTemplates and maxTemplates along with the document and spell checking quotas.
Check Whether a Template Exists
Before a merge names a template, or before an upload would replace one, ask the storage whether the name is taken:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/exists?templateName=sample_invoice.tx"
The answer is true or false. Unlike the other endpoints that take a name, exists doesn't answer 400 for a name that is not stored.
Read the Merge Fields and Blocks of a Template
GET /v1/templates/info opens a stored template and returns its structure, without changing it. A merge field is a placeholder that the merge fills with the value of the JSON property of the same name, and a merge block is a part of the template that the merge repeats for each element of an array, such as a table row per invoice item:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/info?templateName=sample_invoice.tx"
The response for sample_invoice.tx, shortened to one field per level:
{
"templateName": "sample_invoice.tx",
"mergeBlocks": [
{
"name": "item",
"mergeFields": [
{
"dateTimeFormat": "",
"name": "qty",
"numericFormat": "",
"preserveFormatting": false,
"text": "«qty»",
"textAfter": "",
"textBefore": ""
}
],
"mergeBlocks": []
}
],
"mergeFields": [
{
"dateTimeFormat": "",
"name": "invoice_no",
"numericFormat": "",
"preserveFormatting": false,
"text": "«invoice_no»",
"textAfter": "",
"textBefore": "#"
}
],
"userDocumentProperties": {}
}
The TemplateInfo object holds:
| Property | Content |
|---|---|
templateName | The template name as the request gives it, whose case can differ from the name in the storage |
mergeFields | The merge fields outside of any block |
mergeBlocks | The merge blocks, each with its name, its own mergeFields and the mergeBlocks nested in it |
userDocumentProperties | The user-defined document properties, as names and values |
Each merge field has a name, the formats dateTimeFormat and numericFormat it applies to date and numeric values, preserveFormatting, which says whether the formatting is preserved, its displayed text and the texts before and after the field, textBefore and textAfter. A block lists only its own fields and blocks, so walk the nested blocks to see the whole structure.
Your application can use the structure before it merges, for example to compare the field names with the keys of its JSON data, to check that it has an array for each block, or to build an input form with one field per merge field and merge the values the user enters. Merge Fields and Merge Blocks show how names and data match.
Count the Pages of a Template
GET /v1/templates/pagecount returns the number of pages of a stored template as a plain number:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/pagecount?templateName=sample_invoice.tx"
The number tells you, for example, which pages exist before you ask GET /v1/templates/thumbnails for images of a page range, as Thumbnails shows.
Download a Template
GET /v1/templates/download returns a stored template as a Base64 string in a JSON string. The following commands save sample_invoice.tx to a local file:
curl "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/download?templateName=sample_invoice.tx" \
template.json
# Decode the Base64 string of the response
jq . template.json | base64 > sample_invoice.tx
jq -r . removes the quotes of the JSON string, and base64 -d decodes it into the file.
Delete a Template
DELETE /v1/templates/delete removes a template from the storage and frees its place in the template storage quota:
curl DELETE "Authorization: ReportingCloud-APIKey $REPORTINGCLOUD_API_KEY" \
"https://api.reporting.cloud/v1/templates/delete?templateName=invoice.docx"
The answer 204 No Content has no body. A merge that names the deleted template afterward is refused with 400 Bad Request.
Manage Templates With .NET
The NuGet package TXTextControl.ReportingCloud sends the same requests from C#. The following console application uploads invoice.docx unless the storage already has a template of this name, lists the stored templates and prints the merge structure of the uploaded one:
using TXTextControl.ReportingCloud;
var rc = new ReportingCloud(Environment.GetEnvironmentVariable("REPORTINGCLOUD_API_KEY"));
// Upload the template only if the storage has none of this name
if (!rc.TemplateExists("invoice.docx"))
{
rc.UploadTemplate("invoice.docx", File.ReadAllBytes("invoice.docx"));
}
foreach (Template template in rc.ListTemplates())
{
Console.WriteLine($"{template.TemplateName}: {template.Size} bytes, changed {template.Modified}");
}
TemplateInfo info = rc.GetTemplateInfo("invoice.docx");
foreach (MergeField field in info.MergeFields)
{
Console.WriteLine($"Field: {field.Name}");
}
foreach (MergeBlock block in info.MergeBlocks)
{
PrintBlock(block, 0);
}
// Prints a block with its fields and, indented, the blocks nested in it
void PrintBlock(MergeBlock block, int level)
{
string indent = new string(' ', level * 2);
Console.WriteLine($"{indent}Block: {block.Name}");
foreach (MergeField field in block.MergeFields)
{
Console.WriteLine($"{indent} Field: {field.Name}");
}
foreach (MergeBlock nested in block.MergeBlocks)
{
PrintBlock(nested, level + 1);
}
}
The code works as follows:
- The
ReportingCloudconstructor takes the API key. The class sends it in theAuthorizationheader of every request tohttps://api.reporting.cloud. TemplateExistsandUploadTemplatecallGET /v1/templates/existsandPOST /v1/templates/upload.UploadTemplatetakes the name in the storage and the template as a byte array, and does the Base64 encoding.ListTemplatesreturns a list ofTemplateobjects withTemplateName,ModifiedandSize.GetTemplateInforeturns aTemplateInfoobject whoseMergeFieldsandMergeBlocksholdMergeFieldandMergeBlockobjects, soPrintBlockcalls itself for each nested block.
Each endpoint of the storage has a method in the .NET and the PHP SDK:
| Endpoint | .NET | PHP |
|---|---|---|
templates/upload | UploadTemplate(templateName, template) | uploadTemplate($templateFilename), uploadTemplateFromBase64($data, $templateName) |
templates/list | ListTemplates() | getTemplateList() |
templates/count | GetTemplateCount() | getTemplateCount() |
templates/exists | TemplateExists(templateName) | templateExists($templateName) |
templates/info | GetTemplateInfo(templateName) | getTemplateInfo($templateName) |
templates/pagecount | GetTemplatePageCount(templateName) | getTemplatePageCount($templateName) |
templates/download | DownloadTemplate(templateName) | downloadTemplate($templateName) |
templates/delete | DeleteTemplate(templateName) | deleteTemplate($templateName) |
A refused request makes the .NET methods throw an ArgumentException and the PHP methods a RuntimeException, as Handle Errors in the SDKs describes. .NET and PHP in the SDKs section show how to install and set up each SDK.
Next Steps
- Template Storage: upload, create and delete templates in the portal.
- Overview: merge a stored template, or one sent with the request, with JSON data.
- Thumbnails: render the pages of a stored template as images.
- Sharing Documents: show a stored document on a web page.
- Errors and Status Codes: what a refused request means.