Files
2026-07-12 10:17:17 -04:00

76 lines
3.2 KiB
Markdown

# PocketBase Data Normalization Pitfalls
## JSON fields come back as strings
PocketBase's `json` field type does NOT guarantee parsed JSON arrays on read. The SDK may return JSON fields as **serialized strings** instead of parsed arrays/objects. Always normalize after fetching:
```typescript
const records = await pb.collection('repairOrders').getList(1, 200, { ... });
const normalized = records.items.map((item: any) => {
let services = item.services || [];
if (typeof services === 'string' && services.trim()) {
try { services = JSON.parse(services); } catch { services = []; }
}
if (!Array.isArray(services)) services = [];
return { ...item, services };
});
```
**Symptom:** `e.reduce is not a function` or `e.map is not a function` on fields you expected to be arrays.
**Also affects:** edit modals that pre-populate from fetched records — apply the same normalization before `setState()`.
## Empty/malformed JSON strings
Even when a JSON field has a value, it might be an empty string `""` or partially corrupted. JSON.parse on these throws `"Unexpected end of JSON input"`. Always wrap in try/catch:
```typescript
try { parsed = JSON.parse(raw); } catch { parsed = []; }
```
## Missing system fields (created, updated)
Some PocketBase collections lack the standard `created`/`updated` auto-fields. This happens when collections were created via raw SQL or imported. **Symptom:** queries with `sort: '-created'` or `fields: '...,created'` return 400 errors.
**Fix:** Use `sort: '-id'` (PocketBase IDs are time-sortable) and avoid requesting `created`/`updated` in the `fields` parameter.
**Detection:** Test with `curl` first:
```bash
curl -s "http://127.0.0.1:8091/api/collections/NAME/records?sort=-created&perPage=1" \
-H "Authorization: $TOKEN"
```
If it returns 400, the collection lacks `created`.
## Collection naming conventions
PocketBase collection names are case-sensitive. `repairOrders` and `repair_orders` are different collections. When porting from one naming convention to another, test each collection name directly against the API.
**Detection:**
```python
for name in ['repairOrders', 'repair_orders', 'repairorders']:
r = fetch(f'http://127.0.0.1:8091/api/collections/{name}/records?perPage=1')
print(f"{name}: {'EXISTS' if r.status == 200 else 'MISSING'}")
```
## PocketBase SDK error structure
The `ClientResponseError` thrown by the PocketBase JS SDK has this shape:
```
error.message → top-level message ("Failed to create record.")
error.status → HTTP status (400)
error.response → full API response body: {
data: { email: { message: "Value must be unique." } },
message: "Failed to create record.",
status: 400
}
```
For field-level validation errors, access `error.response.data`. Do NOT assume `error.data` is the field errors — in some SDK versions `error.data` is an alias for `error.response` (the full response body), so field errors are at `error.response.data` or `error.data.data`.
Simple reliable pattern:
```typescript
const message = err instanceof Error ? err.message : 'Failed';
```
The PocketBase SDK's `.message` already includes the user-facing error text.