API V3: Implement Structured Error Handling and Validation Tests
- Updated api_get_object and api_post_object to extract rich metadata (meta.details) from 400/500 responses. - Enables frontend to bubble up specific DB schema, validation, and constraint errors for better debugging. - Added 'V3 Hardening' section to /testing dashboard with automated tests for Permissive Mode and Structured Error extraction.
This commit is contained in:
@@ -176,6 +176,53 @@
|
||||
return await response.json();
|
||||
});
|
||||
|
||||
// V3 Schema & Error Validation
|
||||
const test_permissive_mode = () => run_test('Permissive Mode Test', async () => {
|
||||
const endpoint = `/v3/crud/account/${$ae_loc.account_id || 'ghost'}`;
|
||||
const data = {
|
||||
name: $ae_loc.account_name,
|
||||
_non_existent_field: 'This should be ignored by the API'
|
||||
};
|
||||
// Use post_object for a patch-like operation if needed, or update_ae_obj_v3 style
|
||||
// For testing purposes, we'll use a standard fetch to see raw response
|
||||
const url = new URL(endpoint, $ae_api.base_url);
|
||||
const headers = {
|
||||
...$ae_api.headers,
|
||||
'x-account-id': $ae_loc.account_id || 'ghost',
|
||||
'Authorization': `Bearer ${$ae_loc.jwt}`
|
||||
};
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'PATCH',
|
||||
headers,
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
return { status: response.status, result };
|
||||
});
|
||||
|
||||
const test_structured_error = () => run_test('Structured Error Validation (Deliberate 400)', async () => {
|
||||
const endpoint = `/v3/crud/account/${$ae_loc.account_id || 'ghost'}`;
|
||||
// To trigger a 400 error despite permissive mode, we'll try to set a read-only field or invalid type if possible
|
||||
// Actually, the easiest way to test structured error is to send a malformed filter to /search
|
||||
const url = new URL(`${endpoint.split('/account')[0]}/account/search`, $ae_api.base_url);
|
||||
const headers = {
|
||||
...$ae_api.headers,
|
||||
'x-account-id': $ae_loc.account_id || 'ghost',
|
||||
'Authorization': `Bearer ${$ae_loc.jwt}`
|
||||
};
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ and: [{ field: "non_existent", op: "eq", value: "fail" }] })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
return { status: response.status, structured_details: result.meta?.details || 'MISSING' };
|
||||
});
|
||||
|
||||
// Environment Diagnostics
|
||||
let is_native = $derived(typeof window !== 'undefined' && !!(window as any).native_app);
|
||||
let app_mode = $derived($events_loc?.launcher?.app_mode || 'web');
|
||||
@@ -443,6 +490,18 @@
|
||||
<Building2 size={16}/> Load Accounts
|
||||
</button>
|
||||
</div>
|
||||
<div class="card p-6 space-y-4 border border-gray-500 shadow-lg transition-all group hover:bg-surface-500/5">
|
||||
<header class="flex items-center gap-2 text-warning-500 border-b border-gray-500 pb-2">
|
||||
<ShieldAlert size={20}/>
|
||||
<h4 class="h4 font-bold uppercase tracking-widest">V3 Hardening</h4>
|
||||
</header>
|
||||
<button class="btn variant-filled-warning p-4 w-full shadow-md transition-all hover:scale-[1.02] flex items-center justify-center gap-2" disabled={!$ae_loc.jwt} onclick={test_permissive_mode} title="Verifies the API ignores unknown fields (x-ae-ignore-extra-fields).">
|
||||
<Zap size={16}/> Permissive Mode Test
|
||||
</button>
|
||||
<button class="btn variant-filled-error p-4 w-full shadow-md transition-all hover:scale-[1.02] flex items-center justify-center gap-2" disabled={!$ae_loc.jwt} onclick={test_structured_error} title="Deliberately triggers a 400 error to verify rich metadata extraction.">
|
||||
<ShieldAlert size={16}/> Structured Error Test
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Maintenance -->
|
||||
|
||||
Reference in New Issue
Block a user