Skip to content

Instantly share code, notes, and snippets.

@marceldegraaf
Last active September 24, 2025 05:03
Show Gist options
  • Select an option

  • Save marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1 to your computer and use it in GitHub Desktop.

Select an option

Save marceldegraaf/62f5a31d55ac891fa101ebd7454cb0e1 to your computer and use it in GitHub Desktop.
defmodule YourAPp.Gotenberg.Api do
alias YourApp.Gotenberg.Options
require Logger
@timeout 30_000
@doc """
Converts given URL to a PDF binary
"""
@spec html_to_pdf(binary, Options.t()) :: {:ok, binary} | {:error, any}
def html_to_pdf(html, %Options{} = options \\ %Options{}) do
form =
{:multipart,
Options.to_list(options) ++ [{"file", html, {"form-data", [{"name", "file"}, {"filename", "index.html"}]}, []}]}
url("forms/chromium/convert/html")
|> HTTPoison.post(form, [], recv_timeout: @timeout)
|> handle_response()
end
def url(path), do: "#{Application.get_env(:your_app, :gotenberg_host)}/#{path}"
def handle_response({:ok, %HTTPoison.Response{status_code: 200, body: body}}),
do: {:ok, body}
def handle_response({:ok, %HTTPoison.Response{status_code: 404}}),
do: {:error, :not_found}
def handle_response({:ok, %HTTPoison.Response{status_code: 500}}),
do: {:error, :internal_server_error}
def handle_response({:ok, %HTTPoison.Response{status_code: status_code}}),
do: {:error, :"unknown_status_#{status_code}"}
def handle_response({:error, %HTTPoison.Error{reason: reason}}) do
Logger.error("Unexpected error talking to Gotenberg API: #{reason}")
{:error, reason}
end
end
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gotenberg
namespace: prod
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: "100%"
selector:
matchLabels:
app: gotenberg
tier: backend
phase: prod
strategy:
type: Recreate
template:
metadata:
name: gotenberg
labels:
app: gotenberg
tier: backend
phase: prod
spec:
nodeSelector:
preemptible: "true"
tolerations:
- key: AllowPreemptible
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: gotenberg
image: gotenberg/gotenberg:7
securityContext:
privileged: false
runAsUser: 1001
ports:
- containerPort: 3000
readinessProbe:
httpGet:
path: /health
port: 3000
resources:
requests:
memory: 2Gi
cpu: 1
---
apiVersion: v1
kind: Service
metadata:
name: gotenberg
namespace: prod
labels:
app: gotenberg
phase: prod
tier: backend
spec:
type: ClusterIP
ports:
- port: 3000
targetPort: 3000
protocol: TCP
selector:
app: gotenberg
phase: prod
tier: backend
defmodule YourApp.Gotenberg.Options do
alias __MODULE__
@type t() :: %__MODULE__{}
defstruct omit_background: false,
paper_height: 11.7,
paper_width: 8.27,
print_background: true,
landscape: false,
margin_top: 1,
margin_bottom: 1,
margin_left: 1,
margin_right: 1,
scale: 1.0
@spec to_list(Options.t()) :: list()
def to_list(%Options{} = options) do
[
{"omitBackground", "#{options.omit_background}"},
{"paperHeight", "#{options.paper_height}"},
{"paperWidth", "#{options.paper_width}"},
{"printBackground", "#{options.print_background}"},
{"landscape", "#{options.landscape}"},
{"marginTop", "#{options.margin_top}"},
{"marginBottom", "#{options.margin_bottom}"},
{"marginLeft", "#{options.margin_left}"},
{"marginRight", "#{options.margin_right}"},
{"scale", "#{options.scale}"}
]
end
end
defmodule YourApp.YourModule do
def pdf(some_data) do
some_data
|> html()
|> YourApp.Gotenberg.Api.html_to_pdf()
end
def html(some_data) do
Phoenix.View.render_to_string(YourAppWeb.PDFView, "show.html",
locale: some_data.locale,
layout: {YourAppWeb.LayoutView, "pdf.html"},
data: some_data
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment