La génération PDF est devenue un enjeu critique dans bon nombre de projets développés par Digital Garden. Pendant longtemps, notre stack technique s’appuyait sur l’outil open source wkhtmltopdf, reconnu pour sa capacité à convertir des pages HTML/CSS en PDF via le moteur WebKit. Toutefois, ce projet a été officiellement archivé en 2023, posant un problème de maintenance et de compatibilité à long terme.
Dans une logique de continuité de service, de sécurité et de performance, nous avons choisi de migrer vers Gotenberg, une solution moderne et robuste. Il s’agit d’une API en container Docker permettant la conversion de documents (HTML, Markdown, Office...) en PDF, s’intégrant parfaitement dans une architecture microservices. Ce choix technologique offre :
Cette évolution s’inscrit dans notre démarche globale d’amélioration continue et de modernisation des socles techniques utilisés pour accompagner nos clients dans leurs projets à forte valeur ajoutée.
Gotenberg est donc une API de génération PDF indépendante, permettant d’envoyer un document HTML, une url ou encore un fichier libreoffice pour qu’elle nous retourne le binaire d’un PDF.
Dans le cas de Digital Garden, 2points d’entrées sont intéressant :
Cela change l’architecture de ce que nous avions avec wkhtmltopdf. Alors qu’auparavant chaque projet avait son propre générateur de pdf :
A présent nous allons appeler une API Gotenberg mutualisé :
Avantages
Inconvénients
Avantages
Inconvénients
L’installation de l’API Gotenberg se fait très simplement grâce à docker-compose, le service ayant déjà son image docker complète :
// compose.yaml
services:
gotenberg:
image: gotenberg/gotenberg:8 // Nous avons fixé à la version 8, libre à vous d’en utiliser une autre.
command: gotenberg –api-port=80 –api-timeout=60s
ports:
- "10080:80"
Notez la présence de la propriété command qui nous permet de changer la commande par défaut lancée par le container. Ici gotenberg avec les options suivantes :
Ainsi, en allant sur https://localhost:10080 vous devriez voir un lien vers la documentation de Gotenberg. Félicitations, l’API est fonctionnelle.
Pourintégrer Gotenberg à votre application, il existe déjà un bundle créé parSensiolabs, sensiolabs/gotenberg-bundle, quifournit les services utiles pour vous interfacer avec l’API. Cependant, cesservices peuvent être complexes à utiliser (distinction des screenshot et desgénérateurs, envoi des assets liés aux pdf, etc.)
Nousavons donc créé un autre bundle, dgarden/gotenberg-bundle, utilisant lebundle de Sensiolabs, qui donne accès directement aux fonctionnalitéssuivantes :
◦ html() :Permettant de générer un PDF à partir d’un code HTML.
◦ htmlFile() :Permettant de générer un PDF à partir d’un fichier HTML.
◦ merge() : Permettant de fusionner 2 PDF.
◦ mergeWithOptions() :Identique à merge, mais permettant de mettre des options (attention à l’ordre des paramètres, les options sont en premier).
◦ template() : Permet de générer à partir d’un template Twig.
◦ url() :Permet de générer à partir d’une url.
◦ dgarden:pdf:html : Génération d’un PDF à partir d’un fichier html ou de code html.
◦ dgarden:pdf:merge : Fusion de plusieurs PDF.
◦ dgarden:pdf:template : Génération d’un PDF à partir d’un template.
◦ dgarden:pdf:url : Génération d’un PDF à partir d’une url.
D’autres fonctionnalités sont prévues et peut-être déjà implémentés, n’hésitez pas à jeter un coup d’œil aux fichiers TODO.md etCHANGELOG.md dans le repository du projet.
Pour installer le bundle, il vous suffit de lancer la commande :
composer require dgarden/gotenberg-bundle
Comme le suggère l’option api-timeout, la génération du PDF peut prendre un certain temps. C’est pourquoi Gotenberg implémente une génération asynchrone :
Le bundle dgarden/gotenberg-bundle contient déjàtout ce qui est nécessaire pour traiter cette génération asynchrone. Ainsi si vous donnez l’option DigitalGarden\GotenbergBundle\Generator\PdfFileGeneratorOptions::OPTION_ASYNC à vos générations (--async pour les commandes), l’API Gotenberg vous répondra immédiatement, et enverra une requête sur la route ‘/_dg/pdf/generate’ (déjà configurée dans votre router par le bundle).
Par défaut, le bundle va enregistrer les PDF dans le répertoire ‘%kernel.project_dir%/var/pdf’ (modifiable par le paramètre de configuration dgarden.gotenberg.output_path), vous pouvez cependant intercepter ou modifier ce comportement grâce à l’évènement DigitalGarden\GotenbergBundle\Event\PdfGeneratedEvent.
Conclusion
Le projet wkhtmltopdf peut simplement être remplacé par Gotenberg, pouvant ainsi mutualiser la génération des PDF à travers tous nos projets sur une architecture micro-service. De notre expérience, les PDF ainsi générés sont très similaires à ceux générés par wkhtmltopdf, et nous n’avons pas eu à faire de gros changements sur les templates / code de nos applications.
Chez Digital Garden, nous avons l’habitude de concevoir et mettre en œuvre des solutions de génération dynamique de fichiers PDF. Ce savoir-faire s’applique aussi bien à des cas d’usage B2B qu’à des dispositifs à forte dimension B2C :
Hésitez pas à nous contacter si vous avez des problématiques de personnalisation de PDF.