Gotenberg
A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.
Gotenberg is a Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.
Gotenberg is shipped within a Docker image.
You may start it with:
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3
The API will be available at http://localhost:3000.
Or add it in your Docker Compose stack:
version: '3' services: # your others services gotenberg: image: thecodingmachine/gotenberg:3
The API will be available under
gotenberg:3000in your Docker Compose network.
It may also be deployed with Kubernetes.
In the following examples, we will assume your Gotenberg API is available at http://localhost:3000.
$ go get -u github.com/thecodingmachine/gotenberg
Unless your project already has a PSR7 HttpClient, install php-http/guzzle6-adapter:
$ composer require php-http/guzzle6-adapter
Then the PHP client:
$ composer require thecodingmachine/gotenberg-php-client
Gotenberg provides the endpoint /convert/html for HTML conversions.
It accepts POST requests with a multipart/form-data Content-Type.
The only requirement is to send a file named index.html: it is the file
which will be converted to PDF.
For instance:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My PDF</title> </head> <body> <h1>Hello world!</h1> </body> </html>
$ curl --request POST \ --url http://localhost:3000/convert/html \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.HTMLRequest{ IndexFilePath: "index.html", } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\HTMLRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $request = new HTMLRequest($index); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
You may also add a header and/or a footer in the resulting PDF.
Respectively, a file named header.html and footer.html.
Each of them has to be a complete HTML document:
<html> <head> <style> body { font-size: 8rem; margin: 4rem auto; } </style> </head> <body> <p> <span class="pageNumber"></span> of <span class="totalPages"></span> </p> </body> </html>
The following classes allow you to inject printing values:
date: formatted print datetitle: document titlepageNumber: current page numbertotalPage: total pages in the documentAttention: the CSS properties are independant of the ones used in the
index.htmlfile. Also,footer.htmlCSS properties override the ones fromheader.html.
$ curl --request POST \ --url http://localhost:3000/convert/html \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ --form files=@header.html \ --form files=@footer.html \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.HTMLRequest{ IndexFilePath: "index.html", Options: &gotenberg.HTMLOptions{ HeaderFilePath: "header.html", FooterFilePath: "footer.html", }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\HTMLRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $header = DocumentFactory::makeFromPath('header.html', 'header.html'); $footer = DocumentFactory::makeFromPath('footer.html', 'footer.html'); $request = new HTMLRequest($index); $request->setHeader($header); $request->setFooter($footer); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
You may also send additional files. For instance: images, fonts, stylesheets and so on.
The only requirement is to make sure that their paths
are on the same level as the index.html file.
In others words, this will work:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My PDF</title> </head> <body> <h1>Hello world!</h1> <img src="img.png"> </body> </html>
But this won’t:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My PDF</title> </head> <body> <h1>Hello world!</h1> <img src="/foo/img.png"> </body> </html>
You may also use remote paths for Google fonts, images and so on.
If you want to install fonts directly in the Gotenberg Docker image, see to the fonts section.
$ curl --request POST \ --url http://localhost:3000/convert/html \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ --form files=@style.css \ --form files=@img.png \ --form files=@font.woff \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.HTMLRequest{ IndexFilePath: "index.html", AssetFilePaths: []string{ "style.css", "img.png", "font.woff", }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\HTMLRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $assets = [ DocumentFactory::makeFromPath('style.css', 'style.css'), DocumentFactory::makeFromPath('img.png', 'img.png'), DocumentFactory::makeFromPath('font.woff', 'font.woff'), ]; $request = new HTMLRequest($index); $request->setAssets($assets); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
You may also customize the resulting PDF format.
By default, it will be rendered with A4 size, 1 inch margins and portrait orientation.
Paper size and margins have to be provided in
inches. Also, you have to set bothpaperWidthandpaperHeight. Same for margins.
$ curl --request POST \ --url http://localhost:3000/convert/html \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ --form paperWidth=8.27 \ --form paperHeight=11.27 \ --form marginTop=0 \ --form marginBottom=0 \ --form marginLeft=0 \ --form marginRight=0 \ --form landscape=true \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.HTMLRequest{ IndexFilePath: "index.html", Options: &gotenberg.HTMLOptions{ PaperSize: gotenberg.A4, PaperMargins: gotenberg.NoMargins, Landscape: true }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\Request; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $request = new HTMLRequest($index); $request->setPaperSize(Request::A4); $request->setMargins(Request::NO_MARGINS); $request->setLandscape(true); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
Gotenberg provides the endpoint /convert/markdown for Markdown conversions.
It accepts POST requests with a multipart/form-data Content-Type.
Markdown conversions work the same as HTML conversions.
Only difference is that you have access to the Go template function toHTML
in the file index.html. This function will convert a given markdown file to HTML.
For instance:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My PDF</title> </head> <body> {{ toHTML .DirPath "file.md" }} </body> </html>
$ curl --request POST \ --url http://localhost:3000/convert/markdown \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ --form files=@file.md \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.MarkdownRequest{ IndexFilePath: "index.html", MarkdownFilePaths: []string{ "file.md", }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\MarkdownRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $markdowns = [ DocumentFactory::makeFromPath('file.md', 'file.md'), ]; $request = new MarkdownRequest($index, $markdowns); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
Gotenberg provides the endpoint /convert/office for Office document conversions.
It accepts POST requests with a multipart/form-data Content-Type.
You may send one or more Office documents. Following file extensions are accepted:
.doc.docx.odt.xls.xlsx.ods.ppt.pptx.odpAll files will be merged into a single resulting PDF.
Attention: currently,
unoconvcannot perform concurrent conversions. That’s why for Office conversions, the API does only one conversion at a time. See the scalability section to find how to mitigate this issue.
$ curl --request POST \ --url http://localhost:3000/convert/office \ --header 'Content-Type: multipart/form-data' \ --form files=@document.docx \ --form files=@document2.docx \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.OfficeRequest{ FilePaths: []string{ "document.docx", "document2.docx", }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\OfficeRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $files = [ DocumentFactory::makeFromPath('document.docx', 'document.docx'), DocumentFactory::makeFromPath('document2.docx', 'document2.docx'), ]; $request = new OfficeRequest($files); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
By default, only ttf-mscorefonts fonts are installed.
If you wish to use more fonts, you will have to create your own image:
FROM thecodingmachine/gotenberg:3 RUN apt-get -y install yourfonts
Gotenberg provides the endpoint /merge for merging PDFs.
It accepts POST requests with a multipart/form-data Content-Type.
Nothing special here: you may send one or more PDF files and the API will merge them and return the resulting PDF file.
$ curl --request POST \ --url http://localhost:3000/merge \ --header 'Content-Type: multipart/form-data' \ --form files=@file.pdf \ --form files=@file2.pdf \ > result.pdf
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.MergeRequest{ FilePaths: []string{ "file.pdf", "file2.pdf", }, } dest := "result.pdf" c.Store(req, dest) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\MergeRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $files = [ DocumentFactory::makeFromPath('file.pdf', 'file.pdf'), DocumentFactory::makeFromPath('file2.pdf', 'file2.pdf'), ]; $request = new MergeRequest($files); $dirPath = "/foo"; $filename = $client->store($request, $dirPath);
All endpoints accept a form field named webhookURL.
If provided, the API will send the resulting PDF file in a POST request with the application/pdf Content-Type
to given URL.
By doing so, your requests to the API will be over before the conversions are actually done!
$ curl --request POST \ --url http://localhost:3000/convert/html \ --header 'Content-Type: multipart/form-data' \ --form files=@index.html \ --form webhookURL='http://myapp.com/webhook/'
import "github.com/thecodingmachine/gotenberg/pkg" func main() { c := &gotenberg.Client{Hostname: "http://localhost:3000"} req := &gotenberg.HTMLRequest{ IndexFilePath: "index.html", Options: &gotenberg.HTMLOptions{ WebHookURL: "http://myapp.com/webhook/", }, } dest := "result.pdf" resp, err := c.Post(req) }
use TheCodingMachine\Gotenberg\Client; use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\HTMLRequest; $client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client()); $index = DocumentFactory::makeFromPath('index.html', 'index.html'); $request = new HTMLRequest($index); $request->setWebhookURL('http://myapp.com/webhook/'); $resp = $client->post($request);
The API being stateless, you may scale it as much as you want.
For instance, using the following Docker Compose file:
version: '3' services: # your others services gotenberg: image: thecodingmachine/gotenberg:3
You may now launch your services using:
$ docker-compose up --scale gotenberg=your_number_of_instances
When requesting the Gotenberg service with your client(s), Docker will automatically redirect a request to a Gotenberg container according to the round-robin strategy.
Psst: TheCodingMachine is always looking for talented coders.