docs(api-guide): document flat vs nested URL path rules (section 4)
Describes which object types are always-flat (never nested in URL) for ALL operations, vs event sub-objects which use nested paths for mutations but flat paths for all reads (GET, list, search, delete). Always-flat objects: - Core: account, activity_log, address, contact, hosted_file, organization, page, person, site, user - Other: archive, event, journal, post Event sub-objects (event_badge, event_session, etc.) use nested create_nested_obj_v3 / update_nested_obj_v3 for POST/PATCH, but flat paths for everything else. Includes Playwright mock URL patterns for each operation type.
This commit is contained in:
@@ -70,7 +70,77 @@ Modify data in the system.
|
||||
|
||||
---
|
||||
|
||||
## 4. V3 Uniform Lookup System
|
||||
## 4. Flat vs Nested URL Paths
|
||||
|
||||
This is the single most common source of mock errors in Playwright tests. The V3 API has two URL structures and the right one to use depends on the object type and the operation.
|
||||
|
||||
### Always-Flat Objects
|
||||
|
||||
These object types use flat paths for **every** operation — GET, list, search, create, update, delete. They are never children in a nested URL.
|
||||
|
||||
**Core modules:**
|
||||
`account`, `activity_log`, `address`, `contact`, `hosted_file`, `organization`, `page`, `person`, `site`, `user`
|
||||
|
||||
**Other modules:**
|
||||
`archive`, `event`, `journal`, `post`
|
||||
|
||||
All operations for these objects use the flat helpers:
|
||||
| Operation | Function | URL pattern |
|
||||
|---|---|---|
|
||||
| GET single | `api.get_ae_obj_v3` | `/v3/crud/{obj_type}/{id}` |
|
||||
| GET list | `api.get_ae_obj_li_v3` | `/v3/crud/{obj_type}/?for_obj_id=...` |
|
||||
| Search | `api.search_ae_obj_v3` | `/v3/crud/{obj_type}/search` |
|
||||
| Create | `api.create_ae_obj_v3` | `/v3/crud/{obj_type}/` |
|
||||
| Update | `api.patch_ae_obj_v3` | `/v3/crud/{obj_type}/{id}` |
|
||||
| Delete | `api.delete_ae_obj_v3` | `/v3/crud/{obj_type}/{id}` |
|
||||
|
||||
### Nested Objects (Event Sub-objects)
|
||||
|
||||
Objects that belong to a parent (e.g. `event_badge`, `event_session`, `event_badge_template`, `event_file`, `event_presenter`, `event_presentation`, `event_device`, `event_location`) use **nested paths for mutations** but **flat paths for reads**.
|
||||
|
||||
| Operation | Function | URL pattern |
|
||||
|---|---|---|
|
||||
| GET single | `api.get_ae_obj_v3` | `/v3/crud/{obj_type}/{id}` ← **flat** |
|
||||
| GET list | `api.get_ae_obj_li_v3` | `/v3/crud/{obj_type}/?for_obj_id=...` ← **flat** |
|
||||
| Search | `api.search_ae_obj_v3` | `/v3/crud/{obj_type}/search` ← **flat** |
|
||||
| Create | `api.create_nested_obj_v3` | `/v3/crud/{parent_type}/{parent_id}/{child_type}/` ← **nested** |
|
||||
| Update | `api.update_nested_obj_v3` | `/v3/crud/{parent_type}/{parent_id}/{child_type}/{child_id}` ← **nested** |
|
||||
| Delete | `api.delete_ae_obj_v3` | `/v3/crud/{obj_type}/{id}` ← **flat** |
|
||||
|
||||
**Example — `event_badge` under event `abc123`:**
|
||||
```
|
||||
GET /v3/crud/event_badge/badge-xyz ← flat (get_ae_obj_v3)
|
||||
GET /v3/crud/event_badge/?for_obj_id=abc123 ← flat (get_ae_obj_li_v3)
|
||||
POST /v3/crud/event_badge/search ← flat (search_ae_obj_v3)
|
||||
POST /v3/crud/event/abc123/event_badge/ ← nested (create_nested_obj_v3)
|
||||
PATCH /v3/crud/event/abc123/event_badge/badge-xyz ← nested (update_nested_obj_v3)
|
||||
DELETE /v3/crud/event_badge/badge-xyz ← flat (delete_ae_obj_v3)
|
||||
```
|
||||
|
||||
### Playwright Mock Rule of Thumb
|
||||
|
||||
Since all reads are flat, the most common mock patterns are:
|
||||
```typescript
|
||||
// ✅ Search (always flat)
|
||||
url.includes('/v3/crud/event_badge/search') && method === 'POST'
|
||||
|
||||
// ✅ List (always flat, filter by query param)
|
||||
url.includes('/v3/crud/event_badge/') && url.includes('for_obj_id') && method === 'GET'
|
||||
|
||||
// ✅ GET single (always flat)
|
||||
url.includes('/v3/crud/event_badge/badge-xyz') && method === 'GET'
|
||||
|
||||
// ✅ Create (nested for event sub-objects)
|
||||
url.match(/\/v3\/crud\/event\/[^/]+\/event_badge\/$/) && method === 'POST'
|
||||
|
||||
// ✅ Update (nested for event sub-objects)
|
||||
url.match(/\/v3\/crud\/event\/[^/]+\/event_badge\/badge-xyz/) && method === 'PATCH'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. V3 Uniform Lookup System
|
||||
<!-- was section 4 -->
|
||||
|
||||
The V3 Lookup system provides a hierarchical, deduplicated interface for standardized tables (Countries, Timezones, etc.). It supports global defaults, account overrides, and site-specific whitelisting.
|
||||
|
||||
@@ -104,7 +174,7 @@ To limit lookups for a specific site, add a `lookup_policy` to the `site.cfg_jso
|
||||
|
||||
---
|
||||
|
||||
## 5. Event File Data Retrieval (Hosted Files)
|
||||
## 6. Event File Data Retrieval (Hosted Files)
|
||||
|
||||
Every Event File (`event_file`) **must** have a linked Hosted File (`hosted_file`). The Hosted File itself is a metadata record for binary content (files), which is accessed via separate Action endpoints (e.g., `/v3/action/hosted_file/download`). This API endpoint provides metadata about the associated hosted file. To retrieve this additional metadata:
|
||||
|
||||
@@ -123,7 +193,7 @@ Every Event File (`event_file`) **must** have a linked Hosted File (`hosted_file
|
||||
|
||||
---
|
||||
|
||||
## 5. Troubleshooting 403 Forbidden
|
||||
## 7. Troubleshooting 403 Forbidden
|
||||
|
||||
If you receive a 403 on a valid ID:
|
||||
1. Verify `x-aether-api-key` is correct.
|
||||
|
||||
Reference in New Issue
Block a user