initial commit
This commit is contained in:
+75
@@ -0,0 +1,75 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user