initial commit
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
# PocketBase SDK Path Construction
|
||||
|
||||
## The double `/api` trap
|
||||
|
||||
When building a reverse proxy for a PocketBase-backed SPA, the PB JS SDK constructs its own API paths. Understanding this avoids the most common proxy bug.
|
||||
|
||||
### How the PB SDK builds URLs
|
||||
|
||||
The PocketBase JS SDK's `buildURL` method concatenates `baseURL` + `path`:
|
||||
|
||||
```js
|
||||
// If you create: new PocketBase('/pb')
|
||||
// Then calling pb.collection('users').authWithPassword(email, password)
|
||||
// SDK builds: GET /pb/api/collections/users/auth-with-password
|
||||
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// baseURL SDK-added /api/ path
|
||||
```
|
||||
|
||||
The SDK ALWAYS prepends `/api/` to its paths. Your proxy must strip only the `/pb` prefix and forward the rest as-is — including the `/api/` that the SDK already added.
|
||||
|
||||
### The bug
|
||||
|
||||
```python
|
||||
# WRONG — this adds a second /api/, producing /api/api/collections/...
|
||||
if self.path.startswith('/pb'):
|
||||
url = PB_BACKEND + '/api' + self.path[3:] # DOUBLE /api!
|
||||
```
|
||||
|
||||
PocketBase returns `404 {"message": "The requested resource wasn't found."}` for the double-path URL, which is the same error message as genuinely missing resources — making this a silent, confusing failure.
|
||||
|
||||
### The fix
|
||||
|
||||
```python
|
||||
# CORRECT — preserve the original path, which already includes /api/
|
||||
if self.path.startswith('/pb'):
|
||||
url = PB_BACKEND + self.path[3:] # /pb/X → /X on backend
|
||||
```
|
||||
|
||||
## Python `http.server` path behavior
|
||||
|
||||
`BaseHTTPRequestHandler.path` includes the query string. When forwarding, the query string is already part of the path. `urllib.request.Request(url)` handles query strings correctly, so no special parsing is needed.
|
||||
|
||||
## PocketBase admin auth
|
||||
|
||||
PocketBase admin/superuser authentication is version-dependent:
|
||||
|
||||
- **v0.22+**: `POST /api/collections/_superusers/auth-with-password`
|
||||
- **Older**: `POST /api/admins/auth-with-password` (may be a 404)
|
||||
- The admin dashboard is at `/_/` (web UI only, not an API endpoint)
|
||||
|
||||
If neither endpoint works, check the PocketBase version. The admin user must be created via the `./pocketbase superuser` CLI command or through the web UI on first run.
|
||||
|
||||
## PocketBase Query Field Errors (400 "Something went wrong")
|
||||
|
||||
PocketBase returns `400 {"message": "Something went wrong while processing your request."}` when a query references fields that don't exist in the collection schema. This is NOT a 404 — it's a 400, and the error message is generic, making it easy to misdiagnose as a permissions or setup issue.
|
||||
|
||||
### The `created` / `updated` system field trap
|
||||
|
||||
Collections created via the PocketBase API (rather than the admin UI) may lack the `created` and `updated` system fields. Any query that sorts or filters on these fields will fail with 400.
|
||||
|
||||
**Symptom:** `sort: '-created'` succeeds via curl against a valid collection but returns 400 when tested against the same collection on a different PB instance. The collection EXISTS but the query fails because the field doesn't.
|
||||
|
||||
**Detection:** Test the exact query parameters one at a time:
|
||||
```python
|
||||
# Isolate which parameter breaks
|
||||
# Test: ?page=1 (should work)
|
||||
# Test: ?page=1&sort=-created (fails → field missing)
|
||||
# Test: ?page=1&fields=created (may fail or be silently ignored)
|
||||
```
|
||||
|
||||
**Workaround:** Replace `sort: '-created'` with `sort: '-id'` — PocketBase record IDs are sortable and roughly chronological. For `fields`, remove any references to `created`/`updated` if the collection lacks them.
|
||||
|
||||
**Root cause:** Subagents building against one PB instance may use system fields that work there, but the target deployment's PB instance has collections created via API without auto-system-fields enabled.
|
||||
|
||||
### Collection naming mismatches
|
||||
|
||||
PocketBase collection names are case-sensitive and can use either camelCase (`repairOrders`) or snake_case (`repair_orders`) depending on how they were created. The API silently returns 404 for the wrong case, and the error message is identical to a genuinely missing collection. Always verify the exact collection name by querying `GET /api/collections` before assuming a collection doesn't exist.
|
||||
|
||||
## PocketBase Sign-Up Error Handling
|
||||
|
||||
When `pb.collection('users').create()` fails, the PocketBase SDK throws a `ClientResponseError` with a generic top-level `.message` (e.g., `"Failed to create record."`) and field-level details in `.data`:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"email": {"code": "validation_not_unique", "message": "Value must be unique."}
|
||||
},
|
||||
"message": "Failed to create record.",
|
||||
"status": 400
|
||||
}
|
||||
```
|
||||
|
||||
**Never use the raw `.message` directly** — it's always `"Failed to create record."` for any validation failure. Instead, unwrap `.data` to show the user which field failed:
|
||||
|
||||
```typescript
|
||||
} catch (err: unknown) {
|
||||
let message = 'Failed to create account.';
|
||||
if (err && typeof err === 'object' && 'data' in err) {
|
||||
const pbErr = err as { data?: Record<string, { message: string }> };
|
||||
if (pbErr.data) {
|
||||
const fieldErrors = Object.entries(pbErr.data)
|
||||
.map(([field, info]) => `${field}: ${info.message}`)
|
||||
.join('; ');
|
||||
if (fieldErrors) message = fieldErrors;
|
||||
}
|
||||
}
|
||||
setError(message);
|
||||
}
|
||||
```
|
||||
|
||||
This produces user-friendly messages like `email: Value must be unique.` instead of the unhelpful `Failed to create record.`
|
||||
|
||||
Common PocketBase validation errors on user creation:
|
||||
- **email not unique** → `email: Value must be unique.`
|
||||
- **password too short** → `password: Must be at least 8 characters.`
|
||||
- **missing required field** → `email: Cannot be blank.`
|
||||
|
||||
## PocketBase SMTP Configuration
|
||||
|
||||
PocketBase requires SMTP to be configured for email verification to work. Check the `_params` table in the PocketBase data directory:
|
||||
|
||||
```sql
|
||||
SELECT value FROM _params WHERE id='settings'
|
||||
```
|
||||
|
||||
If `smtp.enabled` is `false`, verification emails will never send. Configure SMTP via the PocketBase admin UI (`/_/`) or by updating the `_params` row directly with valid SMTP credentials (host, port, username, password, TLS).
|
||||
Reference in New Issue
Block a user