IV.3
Export forms to PDF on the server
You need this: When the PDF must be produced server-side (archiving, email attachments) rather than in the user's browser.
PDF Generator runs on plain Node.js, without a browser. Give it the definition and the answers; get back the filled form. Here the SurveyJS service produces it next to this app, and the route passes the bytes through.
This step on the Server Integration page
Source on GitHub
Commercial licence: without SURVEYJS_LICENSE_KEY the component shows a licence banner
The SurveyJS service is called at http://surveyjs:3000. If it isn't running, the endpoint answers
503 "SurveyJS service is not running": start it with docker compose up -d surveyjs.
PDF Generator is commercial. The pinned SurveyJS service never calls setLicenseKey(), so its PDFs carry the SurveyJS alert banner even when you set a licence key.
Try this
- Claim #1 · dana.reyes@example.com
- Claim #2 · li.wei@example.com
- Claim #3 · sam.osei@example.com
Code that just ran
These regions are read from the files that served this page, the same lines the Server Integration page shows.
shared/client/server-pdf.js · sjs:IV.3.client
View on GitHub
// Ask your server for the filled form as a PDF
async function openPdf(id) {
const tab = window.open("", "_blank"); // open the tab in the click itself: after an await, browsers block pop-ups
const res = await fetch(`/api/claims/${id}/pdf`);
if (!res.ok) {
tab.close();
throw new Error((await res.json()).error);
}
tab.location = URL.createObjectURL(await res.blob());
}
routes/examples/server-pdf.php · sjs:IV.3.server
View on GitHub
// GET /api/claims/{id}/pdf — ask the SurveyJS service for the filled form and pass the PDF through
Route::get('/api/claims/{id}/pdf', function (string $id) {
$data = DB::table('responses')->where('form_id', 'claim')->where('id', $id)->value('data') ?? abort(404, 'Unknown claim');
$definition = DB::table('forms')->where('key', 'claim')->value('json');
try {
$pdf = Http::baseUrl(config('surveyjs.service_url'))->timeout(60)
->post('/pdf', ['schema' => json_decode($definition), 'response' => json_decode($data)]);
} catch (ConnectionException $e) { // cURL error 28 is a timeout
return str_contains($e->getMessage(), 'cURL error 28')
? response()->json(['error' => 'SurveyJS service timed out'], 504)
: response()->json(['error' => 'SurveyJS service is not running at '.config('surveyjs.service_url')], 503);
}
if ($pdf->status() !== 200 || ! str_starts_with($pdf->header('Content-Type'), 'application/pdf')) { // fail closed
Log::error('SurveyJS service: unexpected answer from /pdf', ['status' => $pdf->status(), 'body' => substr($pdf->body(), 0, 2000)]);
return response()->json(['error' => 'SurveyJS service error'], 502);
}
return response($pdf->body(), 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => "inline; filename=\"claim-{$id}.pdf\"",
]);
});
Definition: shared/definitions/relational-storage.v1.json