Send a tampered response
Source on GitHub
Definition: shared/definitions/relational-storage.v1.json
shared/client/validate-response.js · sjs:validate-response.client
View on GitHub
// Show the server's verdict in the completion message
survey.onComplete.add(async (sender, options) => {
options.showSaveInProgress();
const res = await fetch("/api/responses", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ formId: "claim", data: sender.data })
});
if (res.ok) return options.showSaveSuccess();
const { errors, error } = await res.json();
options.showSaveError(errors ? errors.map(describe).join("; ") : error);
});
routes/examples/validate-response.php · sjs:validate-response.server
View on GitHub
// POST /api/responses — ask the SurveyJS service to validate, then store as usual
Route::post('/api/responses', function (Request $request) {
$body = json_decode($request->getContent(), flags: JSON_THROW_ON_ERROR); // the raw body keeps {} as {} (see Save Responses)
$definition = DB::table('forms')->where('key', $body->formId ?? null)->value('json') ?? abort(404, 'Unknown form');
$check = SurveyJsService::post('/response', ['schema' => json_decode($definition), 'response' => $body->data ?? null], timeout: 10);
if ($check->status() === 422 && $check->json('errors') !== null && ! array_key_exists('warnings', $check->json())) {
return response()->json(['errors' => $check->object()->errors], 400); // the answers don't fit the definition
}
if ($check->status() !== 200 || $check->body() !== '{}') { // fail closed: only exactly {} means valid
SurveyJsService::unexpected('/response', $check, $check->status() === 422 && $check->json('warnings') !== null ? 'The stored definition has errors' : 'SurveyJS service error');
}
$id = StoredJson::insertResponse($body->formId, $body->data); // stored as it arrived: 1.0 stays 1.0
return response()->json(['id' => $id], 201);
});