The docker image allows you to run docxtemplater with all 18 docxtemplater modules contained in the ENTREPRISE plan, without having to configure them. The modules are already configured to sane defaults (and customizable) and work well with each other.
We have developped manys sdks in multiple languages to allow you to generate your documents from those languages :
After downloading the docker image, you can find all sdks in the sdk/
folder for example : sdk/php/
.
The API exposes an HTTP POST
route to do the generation that takes as input the template file and the data to be used for the generation.
The API outputs the generated file as docx, pptx or xlsx.
The docker image can be used to generate documents from other languages (Java, .Net), since it only requires to do one HTTP Call.
View the OpenAPI Specification of the API
This example requires you to have input.docx, data.json and it exports output.docx
# creates a new file descriptor 3 that redirects to 1 (STDOUT)
exec 3>"output.docx"
# Run curl in a separate command,
# capturing output of -w "%{http_code}" into HTTP_STATUS
# and sending the content to this command's STDOUT with -o >(cat >&3)
curl --silent \
-X POST \
-F "data=@data.json" \
-F "filecomment=This is an image file" \
-F "doc=@input.docx" \
-w "%{http_code}" \
"$host/api/v1/generate" \
-o >(cat >&3) >/tmp/httpstatus || code="$?"
It is also possible to get the list of tags in a template (no generation done, by using following script :
curl --silent \
-X POST \
-F "doc=@input.docx" \
"$host/api/v1/retrieve-tags" || code="$?"
It is possible to get the list of tags separated using the structure of the document :
curl --silent \
-X POST \
-F "doc=@input.docx" \
"$host/api/v1/retrieve-tags?format=separated" || code="$?"
This will return :
for pptx : tags separated by slide :
[
{
"slide": 1,
"tags": {
"title": {},
"description": {}
}
},
{
"slide": 2,
"tags": {
"users": {
"id": {},
"name": {},
"occupation": {},
"age": {}
}
}
}
]
for xlsx, separated by sheets :
[
{
"sheetName": "Sheet1",
"target": "xl/worksheets/sheet1.xml",
"tags": {
"name": {},
"items.length": {},
"totalPrice": {},
"discount": {},
"items": {
"name": {},
"quantity": {},
"unit_price": {},
"quantity \* unit_price.value": {}
}
}
}
]
for docx, separated by headers/footers and document :
{
"headers": [
{
"target": "word/header1.xml",
"tags": {
"last_name": {},
"first_name": {},
"phone": {},
"description": {}
}
}
],
"footers": [
{
"target": "word/footer1.xml",
"tags": {
"last_name": {},
"first_name": {},
"phone": {}
}
}
],
"document": {
"target": "word/document.xml",
"tags": {
"last_name": {},
"first_name": {}
}
}
}
It is possible to configure your instance by editing the configuration.js
file.
There are different parts that you can configure.
By implementing configureAngularParser
, you can add angular filters that you want to be able to use in your template :
const configuration = {
/* Other methods ... */
configureAngularParser(expressions) {
/*
* Here you can define custom filters
* For example if you wish to write { clientName | upper }
*/
expressions.filters.upper = function (input) {
/*
* Make sure that if your input is undefined, your
* output will be undefined as well and will not
* throw an error
*/
if (!input) {
return input;
}
return input.toUpperCase();
};
return expressions;
},
};
By implementing configureDocxtemplater
, you can attach additional modules that you have developped yourself.
const configuration = {
/* Other methods ... */
configureDocxtemplater(doc) {
/*
* Here you can configure the docxtemplater instance before compiling/rendering
* For example :
*
* doc.attachModule(new MyCustomModule());
*/
return doc;
},
};
By implementing configureModule
, you can modify the configuration of a given module.
const configuration = {
/* Other methods ... */
configureModule(moduleName, options) {
/*
* Here you can configure each of the docxtemplater modules
* For example to fetch urls for the image module :
*/
const https = require("https");
const http = require("http");
const Stream = require("stream").Transform;
if (moduleName === "image") {
options.getImage = function (url) {
return new Promise(function (resolve, reject) {
(url.substr(0, 5) === "https" ? https : http)
.request(url, function (response) {
if (response.statusCode !== 200) {
return reject(
new Error(
`Request to ${url} failed, status code: ${response.statusCode}`
)
);
}
const data = new Stream();
response.on(
"data",
function (chunk) {
data.push(chunk);
}
);
response.on("end", function () {
resolve(data.read());
});
response.on("error", function (e) {
reject(e);
});
})
.end();
});
};
}
return options;
},
};
By implementing postrender
or prerender
, you can run some code right before or right after the rendering of your document.
For example, you could use :
const configuration = {
/* Other methods ... */
prerender(doc, modulesObject) {
// Add a condition, because some modules are not available depending on the filetype (txt/docx/pptx/xlsx)
if (modulesObject.meta) {
/*
* Here you can run code right before rendering
* Right before doc.renderAsync
*/
modulesObject.meta.readonly();
}
},
postrender(doc, modulesObject) {
// Add a condition, because some modules are not available depending on the filetype (txt/docx/pptx/xlsx)
if (modulesObject.meta) {
/*
* Here you can run code right after rendering
* Right after doc.renderAsync
*/
modulesObject.meta.dropLastPageIfEmpty();
}
},
};
Filters make it possible to transform data before showing it to the user using the same concept as unix pipes : it follows the syntax of { data | filterName:args}
.
Input | Output | Description |
---|---|---|
{-2 | abs } | 2 | Get absolute value (always positive) |
{2.5 | round } | 3 | Rounding |
{2.5 | ceil } | 3 | Ceil (get value always rounded up) |
{2.3 | ceil } | 3 | Ceil (get value always rounded up) |
{2.8 | floor } | 2 | Floor (get value always rounded down) |
{2.8 | toFixed } | '2' | Stringify value with optional precision |
{2.8 | toFixed } | '2' | Stringify value with optional precision |
{2.855 | toFixed:1 } | '2.8' | Stringify value with optional precision |
Input | Output | Description |
---|---|---|
{["a", "b"] | join:"," } | "a,b" | Join array of strings using a delimiter |
{"a b" | split:" " } | ["a", "b"] | Split string by a delimiter |
{"edgar" | upperCase } | "EDGAR" | Uppercase a string |
{"edgar" | upper} | "EDGAR" | Uppercase a string |
{"Edgar" | lowerCase } | "edgar" | Lowercase a string |
{"Edgar" | lower} | "edgar" | Lowercase a string |
{" abc " | trim } | "abc" | Remove spaces at start and end |
{" abc " | trimStart } | "abc " | Remove spaces at start |
{" abc " | trimEnd } | " abc" | Remove spaces at end |
{ -2 | abs } => return 2
Input | Output | Description |
---|---|---|
{[1,2,3] | min } | 1 | Smallest value |
{[1,2,3] | max } | 3 | Largest value |
{[1,2,3] | sum } | 6 | Sum of multiple numbers |
{users | sumBy:"age" } | 120 | Sum by key |
{[1,2,3] | mean } | 2 | Mean of a set of values |
{users | meanBy:"age" } | 30 | Mean by key |
Input | Output | Description |
---|---|---|
{ _now_ } | Returns the current date | |
{ "2022-01-01T16:00:43+01:00" | formatDate:"YY-M-D" } | 2022-1-1 | YY means Year, M and D for month and date |
{ "2022-01-01T16:00:43+01:00" | formatDate:"h:mm:ss" } | 16:00:43 | Shows the time part |
{ "2022-01-01T16:00:43+01:00" | addDays:2 | formatDate:"YY-M-D" } | 2022-1-3 | Adds two days to a date |
{ "2022-01-01T16:00:43+01:00" | subtractDays:2 | formatDate:"YY-M-D" } | 2021-12-30 | Subtracts two days from a date |
{ "2022-01-01T16:00:43+01:00" | addMonths:2 | formatDate:"YY-M-D" } | 2022-3-1 | Adds two months to a date |
{ "2022-01-01T16:00:43+01:00" | subtractMonths:2 | formatDate:"YY-M-D" } | 2021-11-1 | Subtracts two months to a date |
{ "2022-01-01T16:00:43+01:00" | addYears:2 | formatDate:"YY-M-D" } | 2024-1-1 | Adds two years to a date |
{ "2022-01-01T16:00:43+01:00" | subtractYears:2 | formatDate:"YY-M-D" } | 2020-1-1 | Subtracts two years from a date |
With leftJoin
, rightJoin
, innerJoin
, fullJoin
, you can create joins between two datasets.
This will map the "id" property of a user together with the "orderId" property of an order.
In this sample, the user will be available as the "left" property, and the order as the "right" property.
When you use a join, a "left" and a "right" object is created (the right object can be empty if a user has no orders).
The values that start with _
and end with _
are special "magic values".
Currently, the only value that exists is _now_
, which will return the current date which can be formatted like this :
Any other identifier with the pattern _identifier_
is reserved for future API versions. Examples include:
_xxx_
_time_
Note: Attempting to use reserved magic values that haven't been implemented might cause issues if you upgrade later on.
By default, the docker container will store :
/var/docxstore/:uuid/doc
=> contains the docx file for a given generationAll three of this things can be set to not be logged.
STORE_TEMPLATES
env variable to false
.LOG_REQUESTS
env variable to false
.LOG_ERRORS
env variable to false
.So if you want to stop storing any kind of logs, do the following :
STORE_TEMPLATES=false LOG_REQUESTS=false LOG_ERRORS=false ./run.bash
You can host the docker image on an EC2 Amazon instance for example, or on a virtual machine that you own.
Recommended specs would be :
A decent CPU, the docker image uses only one core (no parallelism in docxtemplater), so you don't "need" a 16 CPU server. (But you can have one instance of the docker image for each CPU if you expect very high load). Docxtemplater is CPU bound, meaning that to improve the speed of your docker instance, the most useful thing to do is to upgrade your CPU
2GB of Ram or more for each instance of the docker image
SSD and good network quality cannot hurt as well.
The algorithm for image sizing since version 3.21.0 will :
Calculate the intrinsic image size in pixel of the image coming from your data source.
Calculate the width and height of the container of the {%image} text.
It will then scale the image down if the width of the intrinsic image exceeds that of its container. It will not scale the image up to avoid scaled up images with low quality.
You can also decide to scale up or down some images using following syntax :
{%image | scale:2}
If the intrinsic image size is 100px/100px, it will scale it up to 200px/200px.
{%image | scale:.5}
If the intrinsic image size is 100px/100px, it will scale it down to 50px/50px.
{%image | maxWidth:100}
This will set the maxWidth to 100px, hence the image will not be able to stretch over more than 100px in the word document. If the intrinsic image size is 200px/200px, the final size will be 100px/100px. If the intrinsic size is 60px/60px, the image will not be scaled up, and the final size will be 60px/60px.
{%image | maxWidth:"1in"}
This will set the maxWidth to 1 inch, hence the image will not be able to stretch over more than 1 inch in the word document
It is possible to use a custom certificate by adding your certificate in same folder as the "Dockerfile", simply put your certificate in that folder with the name : ca-certificate.crt
.
That certificate will then be used during the package installation and for requests done using the Imagemodule, using following data for example :
{
"image": "https://docxtemplater.com/puffin.png"
}
openapi: 3.0.0
info:
version: 1.0.0
title: Docxtemplater docker api
description: A docker API that allows to render a docx/pptx/xlsx template with JSON data.
externalDocs:
url: https://docxtemplater.com/docker/
paths:
/api/v1/retrieve-tags:
post:
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
doc:
type: string
format: binary
description: The docx/pptx/xlsx template
required:
- doc
parameters:
- in: query
name: delimiters
schema:
type: string
description: Delimiters that should be used instead of {user}
example: "[[ ]]"
responses:
"200":
description: The list of the tags that are defined in the docxtemplate
/api/v1/generate:
post:
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
data:
type: string
description: The JSON data to apply to the template
example: '{ "name": "John" }'
doc:
type: string
format: binary
description: The docx/pptx/xlsx template
delimiters:
type: string
description: Delimiters that should be used instead of {user}
example: "[[ ]]"
required:
- doc
- data
parameters:
- in: query
name: delimiters
schema:
type: string
description: Delimiters that should be used instead of {user}
example: "[[ ]]"
- in: query
name: imagesize
schema:
type: string
description: Max Image size, in format "<width>x<height>", in pixels, that will not be eceeded
example: "200x300"
responses:
"200":
description: The filled in document
content:
application/vnd.openxmlformats-officedocument.wordprocessingml.document:
schema:
type: string
format: binary
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
schema:
type: string
format: binary
application/vnd.openxmlformats-officedocument.presentationml.presentation:
schema:
type: string
format: binary
headers:
Content-Disposition:
schema:
type: string
example: attachment; filename="generated.docx"
Add format=separated query parameter to /api/v1/retrieve-tags
route.
Use it like this :
/api/v1/retrieve-tags?format=separated
abs
round
ceil
floor
toFixed:precision
split
join
trim
trimStart
trimEnd
upper
lower
min
max
sum
sumBy
mean
meanBy
leftJoin
rightJoin
innerJoin
fullJoin
addDays
subtractDays
addMonths
subtractMonths
addYears
subtractYears
formatDate
buildHttpHeaders
postrender
and prerender
to be able to run steps for metamodule for example before render._now_
which will return the current date. All variables that start with an "" and end with an "" are now reserved for such special values.take
filterslice
filter with 2 argumentsorderBy
filterwhere
filter to work with user created filtersUpdate to not overwrite full expressions.filters object
Bugfix to allow to change the expressions.filters
Also allow to use "configureDocxtemplater" with attachModule.
It is recommended to use the new transformModules
API, but now, the configureDocxtemplater will work with attachModule again :
Update this :
const CommentModule = require("./comment-module.js");
module.exports = {
/* code */
configureDocxtemplater(doc) {
doc.attachModule(new CommentModule());
/*
* Here you can configure the docxtemplater instance before compiling/rendering
* For example :
*
* doc.attachModule(new MyCustomModule());
*/
return doc;
},
};
To this :
const CommentModule = require("./comment-module.js");
module.exports = {
/* code */
transformModules(modules) {
modules.push(new CommentModule());
return modules;
},
};
Fix output of /retrieve-tags
and /retrieve-structured-tags
when the template is invalid, such as :
Fix CVE-2024-54152
(Upgrades to fixed package angular-expressions@1.4.3).
See this github advisory.
configureDocxtemplater
APIIf you're using configureDocxtemplater to add new modules, please convert your code from :
const CommentModule = require("./comment-module.js");
module.exports = {
/* code */
configureDocxtemplater(doc) {
doc.attachModule(new CommentModule());
/*
* Here you can configure the docxtemplater instance before compiling/rendering
* For example :
*
* doc.attachModule(new MyCustomModule());
*/
return doc;
},
};
To this :
const CommentModule = require("./comment-module.js");
module.exports = {
/* code */
transformModules(modules) {
modules.push(new CommentModule());
return modules;
},
};
Update Dockerfile to allow to use a custom ca-certificate
Add to2d
filter for xlsx files
Update retrieve-structured-tags and retrieve-tags to work on invalid template
Update xlsx-module-3.26.1
Update to node 20.18.1
Update to eslint@9, prettier@3.4
Update to docxtemplater@3.51.0
Update table-module-3.23.1
Update subtemplate-module-3.19.0
Update qrcode-module-3.5.0
Update pptx-sub-module-3.1.10
Update meta-module-3.13.0
Update image-module-3.29.4
Update html-module-3.55.1
Update chart-module-3.15.2
.contain
filterAllow to configure following modules in the configuration.js file :
module === "chart"
condition.module === "xlsx"
condition.module === "html-xlsx"
condition.module === "footnote"
condition.module === "table-full"
condition.module === "table-grid"
condition.module === "pptx-sub"
condition.Fix 400 Bad request when sending an XML file (that starts with <?xml version="1.0" encoding="UTF-8"?>
) for text templating.
Allow to change delimiters when using Text templating
Now the output is correct
size
, slice
, link
, chunkBy
, chunk
, recur
ignore_unknown_tags
optionAdd new sdks :
Update modules :
For example :
will now create an image that spans the whole page (or the whole table cell if the tag is placed in a table).
Add POST /retrieve-tags route
Update subtemplate-module-3.13.0
Update paragraph-placeholder-module-3.4.0
Update meta-module-3.4.2
Update image-module-3.21.1
Update html-module-3.37.3
Update chart-module-3.11.0
STORE_TEMPLATES
, LOG_REQUESTS
and LOG_ERRORS
.Add support to change maxWidth/maxHeight of a given image.
You can now write :
{%image | maxWidth:"1cm"}
=> max width of 1 centimeter
{%image | maxWidth:"2in"}
=> max width of 2 inches
{%image | maxWidth:100}
=> max width of 100px
{%image | scale:2}
to create an image which width and height is multiplied by 2.Bugfix to allow to replace images using title field
Fix vulnerability CVE-2020-5219, see advisory and github issue for more detail.
subloop
filter (for xlsx module)First publicly released version