- Extracted journal entry decryption workflow to 'ae_journals_decryption.ts' to decouple it from Svelte reactivity and address loop issues. - Updated 'ae_comp__journal_entry_obj_id_view.svelte' to use the new decryption helper. - Refactored 'Quick Add' to use the first line as the title and remove it from the content before saving.
9.5 KiB
Aether API V3 Frontend Integration Guide (Svelte/TypeScript)
This guide explains how to update or create frontend functions to interact with the new Aether API V3 CRUD endpoints. V3 introduces a nested URL structure, a powerful POST-based search, and improved performance.
1. Key Differences (V2 vs V3)
| Feature | CRUD V2 (Legacy) | CRUD V3 (Modern) |
|---|---|---|
| Base Prefix | /v2/crud |
/v3/crud |
| List Suffix | Uses /list |
No suffix (e.g., /v3/crud/journal/) |
| Nested Path | Not supported in URL | Supported (e.g., /v3/crud/journal/{id}/journal_entry/) |
| View Selection | tbl_alt, mdl_alt |
view parameter (e.g., ?view=enriched) |
| Complex Search | Limited to GET jp |
POST /search (Unlimited size + Hybrid params) |
| Full-Text Search | Manual column names | Reserved q property in SearchQuery |
2. Authentication and Security (Mandatory in V3)
As of January 2026, the V3 architecture enforces strict Multi-Tenant Isolation. Most requests now require valid authentication to prevent data leakage between accounts.
A. Authentication Requirement
Almost all V3 CRUD endpoints require a standard Bearer token in the Authorization header.
- Mandatory: You must provide a valid JWT for nearly all requests.
- Account Isolation: The backend automatically filters all results based on the
account_idfound in your JWT. You cannot access data belonging to another account even if you know the random ID. - Status Codes:
401 Unauthorized: Your JWT is invalid or expired.403 Forbidden: No authentication provided, or you attempted to access an object belonging to a different account.
Example Request Header:
Authorization: Bearer <your_jwt_token>
B. The "Bootstrap Paradox" Exception (site_domain)
There is one critical exception to strict authentication: site_domain search.
Because the frontend needs to lookup the site configuration (to know which account it's on) before a user can log in, the following endpoint allows unauthenticated (guest) access:
Endpoint: POST /v3/crud/site_domain/search
This is the only V3 search allowed without a JWT. All other object types (journal, account, post, etc.) will return 403 Forbidden if accessed without a token.
3. Implementing V3 CRUD Functions
A. List & Single Object (GET)
Support for view selection allows fetching richer data models when needed.
// Example: Get enriched journal details
// GET /v3/crud/journal/{id}?view=enriched
export async function get_ae_obj_v3({ api_cfg, obj_type, obj_id, view = 'default' }) {
const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
return await get_object({ api_cfg, endpoint, params: { view } });
}
B. Advanced & Hybrid Search (POST)
The /search endpoint combines the power of complex logical bodies with the simplicity of query parameters.
export async function search_ae_obj_v3({
api_cfg,
obj_type,
search_query, // { q: "search term", and: [...] }
enabled = 'enabled',
view = 'default',
for_obj_type,
for_obj_id
}) {
const endpoint = `/v3/crud/${obj_type}/search`;
// Standard filters can be passed as query params
const params: any = { enabled, view };
if (for_obj_type) params.for_obj_type = for_obj_type;
if (for_obj_id) params.for_obj_id = for_obj_id;
return await post_object({
api_cfg,
endpoint,
params,
data: search_query
});
}
C. Standardized Global Search (q)
Use the q property in your search body for a keyword search.
- Wildcard Support: Setting
q: "%"will bypass all text filtering and return all records (respecting only logical filters likeenable). - Fallback: If the table lacks a
default_qry_strcolumn, the API automatically performs aLIKEsearch across all searchable fields.
{
"q": "Annual Meeting",
"and": [{ "field": "enable", "op": "eq", "value": true }]
}
4. Create, Update, & Delete (POST, PATCH, DELETE)
V3 supports both top-level operations and nested parent/child operations.
A. Create (POST)
When creating objects, V3 strictly validates the incoming JSON against the mdl_in Pydantic model.
// POST /v3/crud/{obj_type}/
export async function create_ae_obj_v3({ api_cfg, obj_type, data }) {
const endpoint = `/v3/crud/${obj_type}/`;
return await post_object({ api_cfg, endpoint, data });
}
// POST /v3/crud/{parent_obj_type}/{parent_obj_id}/{child_obj_type}/
// Note: Parent ID is automatically injected into the child record.
export async function create_nested_obj_v3({ api_cfg, parent_type, parent_id, child_type, data }) {
const endpoint = `/v3/crud/${parent_type}/${parent_id}/${child_type}/`;
return await post_object({ api_cfg, endpoint, data });
}
B. Update (PATCH)
V3 uses PATCH for partial updates. Only the fields provided in the body will be modified in the database.
// PATCH /v3/crud/{obj_type}/{obj_id}
export async function update_ae_obj_v3({ api_cfg, obj_type, obj_id, data }) {
const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
return await patch_object({ api_cfg, endpoint, data });
}
C. Delete (DELETE)
The DELETE method is used for removal. The backend may implement soft-delete (hide/disable) depending on the configuration.
// DELETE /v3/crud/{obj_type}/{obj_id}
export async function delete_ae_obj_v3({ api_cfg, obj_type, obj_id }) {
const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
return await delete_object({ api_cfg, endpoint });
}
5. Specialized & Context Endpoints
A. Context Resolution (FQDN)
Used during initial load to find the account_id associated with the domain.
Legacy Method: GET /crud/site/domain/{fqdn}?use_alt_table=true&use_alt_base=true
Modern V3 Method (Preferred): POST /v3/crud/site_domain/search with { "q": "your-domain.com" }
B. Schema Discovery
Path: GET /v3/crud/{obj_type}/schema
Used for developer tools or dynamic UI builders to understand the structure of an AE object.
// GET /v3/crud/account/schema
export async function get_obj_schema_v3({ api_cfg, obj_type }) {
const endpoint = `/v3/crud/${obj_type}/schema`;
return await get_object({ api_cfg, endpoint });
}
6. Secure File Downloads (URL Parameter)
For hosted_file and event_file, browsers often need to download files without complex header modifications. In these cases, you can pass the JWT directly in the URL.
// Example: Creating a secure download link for a browser
// GET /v3/crud/hosted_file/{id}/?jwt={token}
const downloadUrl = `${BASE_URL}/v3/crud/hosted_file/${fileId}/?jwt=${jwtToken}`;
7. Best Practices for V3
- Use
viewfor Rich Data: Instead of manually joining data in separate calls, use?view=enrichedor?view=detail. - Singular Nouns: Always use singular names for
obj_type(e.g.,journal). - Strict Typing: Ensure your
dataobjects match the backend models to avoid400 Bad Requestvalidation errors.
8. Standard Patterns & Common Pitfalls (2026 Update)
To ensure stability across the Aether mesh, all frontend components must adhere to these established patterns.
A. The "Whitelist" Standard for Saves
Problem: Sending the entire object returned by a GET request back to a PATCH endpoint will cause a 400 Bad Request. This happens because the object contains technical metadata (like journal_id, created_on, for_type) that the API cannot "SET".
Standard: When preparing a save payload, explicitly whitelist ONLY the user-editable fields.
// ✅ CORRECT: Whitelist only editable fields
const data_kv = {
name: tmp_obj.name,
content: tmp_obj.content,
tags: tmp_obj.tags,
category_code: tmp_obj.category_code
};
// ❌ WRONG: Passing the whole object or just blacklisting a few
const data_kv = { ...tmp_obj };
delete data_kv.id; // Still contains other computed columns!
B. The Triple-ID Save Pattern
Standard: When sending an ID in a POST/PATCH payload (e.g. creating a child object), use the random string version with the _id_random suffix.
- Property:
[obj_type]_id_random - Value: A string (e.g.,
qpgvOh5nOYI)
Warning: Sending a string value under an integer key (e.g. journal_id: "qpgvOh5nOYI") will trigger a Pydantic validation error on the backend.
C. Handle 'NULL' vs '0' for Booleans
Pitfall: Fields like hide or priority can be NULL in the database.
Standard: Ensure your synchronization logic in components handles null, undefined, and 0 identically for boolean checks to prevent "ghost" changes being detected by Svelte 5.
9. Planned API Improvements (2026 Roadmap)
The following refinements have been requested from the Backend Agent to further improve frontend productivity:
- Permissive Update Mode: A new header (
x-ae-ignore-extra-fields: true) is planned to allow the API to ignore non-writable columns inPATCHrequests instead of returning a400 Bad Request. - Automated ID Resolution: Backend will soon support automatic resolution of
_id_randomstrings to integer IDs duringPOST/PATCH, reducing the need for manual lookups in the frontend. - Schema Evolution Tools: New orchestration tools are being developed to automate field creation and renaming, including the automatic regeneration of the enriched SQL views.
- Structured Validation Errors: Move from string-based error details to a machine-readable format for better inline form validation.