I.7
Store responses in a relational database
You need this: When you report on answers with SQL or join them with your own tables.
Always keep the original response JSON and the version of the definition it was filled against. With both, you can re-map old responses whenever your tables change. Then copy the answers you query into columns. valueName makes this safe: it sets the key a question writes into the response independently of the question's name, so a form author can rename or restructure questions in Creator without breaking your columns. For more mapping metadata, such as a column type or a target table, add a custom property to questions; it then appears in Creator's property grid too.
Try this
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/relational-storage.js · sjs:I.7.client
View on GitHub
import { Model, Serializer } from "survey-core";
// Optional: a custom property for richer mapping, editable in Creator's property grid
Serializer.addProperty("question", { name: "dbColumn", category: "data" });
// valueName fixes the key your columns read → response: { "customer_email": "...", "amount": 1840.5 }
const survey = new Model(definitions[definitionVersion]);
// Post the original response with the version of the definition it was filled against
survey.onComplete.add(async (sender) => {
await fetch("/api/claims", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ data: sender.data, definitionVersion })
});
});
routes/examples/relational-storage.php · sjs:I.7.server
View on GitHub
// POST /api/claims — original JSON first, then the columns you query
Route::post('/api/claims', function (Request $request) {
// The raw body, not $request->input(): PHP arrays would turn {} into [] in the stored JSON
$body = json_decode($request->getContent(), flags: JSON_THROW_ON_ERROR);
abort_unless(isset($body->data, $body->definitionVersion), 400, 'Expected { data, definitionVersion }');
$id = DB::transaction(function () use ($body) {
$responseId = DB::table('responses')->insertGetId([
'form_id' => 'claim',
'definition_version' => $body->definitionVersion, // keep the original and its version
'data' => json_encode($body->data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION | JSON_THROW_ON_ERROR),
'created_at' => now('UTC')->toIso8601ZuluString(),
]);
DB::table('claims')->insert([ // keys come from valueName
'response_id' => $responseId,
'customer_email' => $body->data->customer_email ?? null,
'amount' => $body->data->amount ?? null,
]);
return $responseId;
});
return response()->json(['id' => $id], 201);
});
Definition: shared/definitions/relational-storage.v1.json, shared/definitions/relational-storage.v2.json