127 lines
5.8 KiB
Markdown
127 lines
5.8 KiB
Markdown
# 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).
|