397 lines
8.7 KiB
Markdown
397 lines
8.7 KiB
Markdown
# PocketBase API Reference
|
|
|
|
Comprehensive guide to working with PocketBase APIs, SDKs, and common patterns.
|
|
|
|
## Table of Contents
|
|
1. [Installation & Setup](#installation--setup)
|
|
2. [JavaScript SDK](#javascript-sdk)
|
|
3. [REST API](#rest-api)
|
|
4. [Authentication](#authentication)
|
|
5. [CRUD Operations](#crud-operations)
|
|
6. [File Uploads](#file-uploads)
|
|
7. [Real-time Subscriptions](#real-time-subscriptions)
|
|
8. [Error Handling](#error-handling)
|
|
|
|
## Installation & Setup
|
|
|
|
### JavaScript SDK (Browser)
|
|
```html
|
|
<script src="https://unpkg.com/pocketbase@latest/dist/pocketbase.umd.js"></script>
|
|
<script>
|
|
const pb = new PocketBase('http://127.0.0.1:8090');
|
|
</script>
|
|
```
|
|
|
|
### JavaScript SDK (ESM)
|
|
```bash
|
|
npm install pocketbase
|
|
```
|
|
|
|
```javascript
|
|
import PocketBase from 'pocketbase'
|
|
|
|
const pb = new PocketBase('http://127.0.0.1:8090')
|
|
```
|
|
|
|
### Python SDK
|
|
```bash
|
|
pip install pocketbase
|
|
```
|
|
|
|
```python
|
|
from pocketbase import PocketBase
|
|
|
|
pb = PocketBase('http://127.0.0.1:8090')
|
|
```
|
|
|
|
## JavaScript SDK
|
|
|
|
### Initialize Client
|
|
```javascript
|
|
import PocketBase from 'pocketbase'
|
|
|
|
// Browser or ESM
|
|
const pb = new PocketBase('http://127.0.0.1:8090')
|
|
|
|
// Auto-cancel previous requests when new one is fired
|
|
pb.autoCancellation(false)
|
|
```
|
|
|
|
### Authentication
|
|
|
|
**Register User**
|
|
```javascript
|
|
const authData = await pb.collection('users').create({
|
|
email: 'test@example.com',
|
|
password: '123456789',
|
|
passwordConfirm: '123456789',
|
|
name: 'John Doe'
|
|
})
|
|
|
|
// Or with additional profile fields
|
|
const authData = await pb.collection('users').create({
|
|
email: 'test@example.com',
|
|
password: '123456789',
|
|
passwordConfirm: '123456789',
|
|
name: 'John Doe',
|
|
avatar: fileData // File instance
|
|
})
|
|
```
|
|
|
|
**Login**
|
|
```javascript
|
|
const authData = await pb.collection('users').authWithPassword(
|
|
'test@example.com',
|
|
'123456789'
|
|
)
|
|
|
|
// Access auth fields
|
|
console.log(authData.user.email)
|
|
console.log(authData.token) // JWT access token
|
|
```
|
|
|
|
**Login with OAuth2 (Google, GitHub, etc.)**
|
|
```javascript
|
|
const authData = await pb.collection('users').authWithOAuth2({
|
|
provider: 'google',
|
|
code: 'oa2-code-from-provider'
|
|
})
|
|
```
|
|
|
|
**Current Authenticated User**
|
|
```javascript
|
|
// Get current user
|
|
const user = pb.authStore.model
|
|
|
|
// Check if authenticated
|
|
if (pb.authStore.isValid) {
|
|
// User is authenticated
|
|
}
|
|
|
|
// Refresh current user
|
|
const user = await pb.collection('users').authRefresh()
|
|
|
|
// Logout
|
|
pb.authStore.clear()
|
|
```
|
|
|
|
### CRUD Operations
|
|
|
|
**Create Record**
|
|
```javascript
|
|
const record = await pb.collection('posts').create({
|
|
title: 'My First Post',
|
|
content: 'Hello world!',
|
|
author: pb.authStore.model.id // Link to current user
|
|
})
|
|
```
|
|
|
|
**Get Single Record**
|
|
```javascript
|
|
const record = await pb.collection('posts').getOne('RECORD_ID')
|
|
|
|
// With expand
|
|
const record = await pb.collection('posts').getOne('RECORD_ID', {
|
|
expand: 'author'
|
|
})
|
|
|
|
console.log(record.expand?.email) // If author is a relation
|
|
```
|
|
|
|
**Get Multiple Records (List)**
|
|
```javascript
|
|
// Basic list
|
|
const records = await pb.collection('posts').getList(1, 50)
|
|
|
|
// With filtering, sorting, and expansion
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'status = "published"',
|
|
sort: '-created',
|
|
expand: 'author,comments',
|
|
fields: 'id,title,author,created'
|
|
})
|
|
```
|
|
|
|
**Update Record**
|
|
```javascript
|
|
const updated = await pb.collection('posts').update('RECORD_ID', {
|
|
title: 'Updated Title'
|
|
})
|
|
```
|
|
|
|
**Delete Record**
|
|
```javascript
|
|
await pb.collection('posts').delete('RECORD_ID')
|
|
```
|
|
|
|
### Filtering & Querying
|
|
|
|
**Filter Examples**
|
|
```javascript
|
|
// Basic equality
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'status = "published"'
|
|
})
|
|
|
|
// Multiple conditions
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'status = "published" && created >= "2024-01-01"'
|
|
})
|
|
|
|
// Regex
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'title ~ "Hello"'
|
|
})
|
|
|
|
// In array
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'categoryId ~ ["tech", "coding"]'
|
|
})
|
|
|
|
// Null check
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
filter: 'published != null'
|
|
})
|
|
```
|
|
|
|
**Sorting**
|
|
```javascript
|
|
// Sort by single field
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
sort: 'created'
|
|
})
|
|
|
|
// Sort by multiple fields
|
|
const records = await pb.collection('posts').getList(1, 50, {
|
|
sort: 'status,-created'
|
|
})
|
|
```
|
|
|
|
### File Uploads
|
|
|
|
**Upload File**
|
|
```javascript
|
|
const formData = new FormData()
|
|
formData.append('avatar', fileInput.files[0])
|
|
|
|
const updated = await pb.collection('users').update('RECORD_ID', formData)
|
|
```
|
|
|
|
**Get File URL**
|
|
```javascript
|
|
const url = pb.files.getURL(record, record.avatar)
|
|
```
|
|
|
|
**Download File**
|
|
```javascript
|
|
const blob = await pb.files.download(record, record.fileField)
|
|
```
|
|
|
|
### Real-time Subscriptions
|
|
|
|
**Subscribe to Collection**
|
|
```javascript
|
|
// Listen to all record changes in a collection
|
|
pb.collection('posts').subscribe('*', function (e) {
|
|
console.log(e.action) // 'create', 'update', or 'delete'
|
|
console.log(e.record) // The changed record
|
|
})
|
|
```
|
|
|
|
**Subscribe to Specific Record**
|
|
```javascript
|
|
// Listen to changes for a specific record
|
|
pb.collection('posts').subscribe('RECORD_ID', function (e) {
|
|
console.log('Record changed:', e.record)
|
|
})
|
|
```
|
|
|
|
**Unsubscribe**
|
|
```javascript
|
|
// Unsubscribe from specific record
|
|
pb.collection('posts').unsubscribe('RECORD_ID')
|
|
|
|
// Unsubscribe from all posts collection
|
|
pb.collection('posts').unsubscribe()
|
|
|
|
// Unsubscribe from all collections
|
|
pb.collections.unsubscribe()
|
|
```
|
|
|
|
### Batch Operations
|
|
|
|
**Create Multiple Records**
|
|
```javascript
|
|
const promises = records.map(record => {
|
|
return pb.collection('posts').create({
|
|
title: record.title,
|
|
content: record.content
|
|
})
|
|
})
|
|
|
|
const results = await Promise.all(promises)
|
|
```
|
|
|
|
## REST API
|
|
|
|
### Direct HTTP Requests
|
|
|
|
**Get Records**
|
|
```bash
|
|
curl -X GET "http://127.0.0.1:8090/api/collections/posts/records?page=1&perPage=50" \
|
|
-H "Authorization: Bearer JWT_TOKEN"
|
|
```
|
|
|
|
**Create Record**
|
|
```bash
|
|
curl -X POST "http://127.0.0.1:8090/api/collections/posts/records" \
|
|
-H "Authorization: Bearer JWT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "My Post",
|
|
"content": "Content here"
|
|
}'
|
|
```
|
|
|
|
**Update Record**
|
|
```bash
|
|
curl -X PATCH "http://127.0.0.1:8090/api/collections/posts/records/RECORD_ID" \
|
|
-H "Authorization: Bearer JWT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"title": "Updated Title"}'
|
|
```
|
|
|
|
**Delete Record**
|
|
```bash
|
|
curl -X DELETE "http://127.0.0.1:8090/api/collections/posts/records/RECORD_ID" \
|
|
-H "Authorization: Bearer JWT_TOKEN"
|
|
```
|
|
|
|
### File Upload via REST API
|
|
```bash
|
|
curl -X POST "http://127.0.0.1:8090/api/collections/users/records/RECORD_ID" \
|
|
-H "Authorization: Bearer JWT_TOKEN" \
|
|
-F 'avatar=@/path/to/file.jpg'
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### SDK Error Handling
|
|
```javascript
|
|
try {
|
|
const record = await pb.collection('posts').getOne('INVALID_ID')
|
|
} catch (e) {
|
|
// 404: Record not found
|
|
if (e.status === 404) {
|
|
console.log('Record not found')
|
|
}
|
|
|
|
// 403: Permission denied
|
|
if (e.status === 403) {
|
|
console.log('You do not have permission to access this record')
|
|
}
|
|
|
|
// 400: Validation error
|
|
if (e.status === 400) {
|
|
console.log('Validation error:', e.data)
|
|
}
|
|
|
|
console.error('Error:', e.message)
|
|
}
|
|
```
|
|
|
|
### Common HTTP Status Codes
|
|
- **200/201**: Success
|
|
- **400**: Bad Request (validation error)
|
|
- **401**: Unauthorized (not logged in)
|
|
- **403**: Forbidden (permission denied)
|
|
- **404**: Not Found
|
|
- **500**: Internal Server Error
|
|
|
|
### Validation Errors
|
|
```javascript
|
|
try {
|
|
await pb.collection('users').create({
|
|
email: 'invalid-email', // Will fail validation
|
|
password: '123' // Too short
|
|
})
|
|
} catch (e) {
|
|
console.log(e.data) // { email: ['Invalid email'], password: ['Too short'] }
|
|
}
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### CORS Configuration
|
|
Configure CORS in PocketBase settings to allow specific origins:
|
|
|
|
```javascript
|
|
// In admin UI > Settings > CORS
|
|
// Add your frontend origin (e.g., http://localhost:3000)
|
|
```
|
|
|
|
### Environment Variables
|
|
```javascript
|
|
// Production configuration
|
|
const pb = new PocketBase('https://your-production-url.com')
|
|
|
|
// Enable auto-cancellation in production
|
|
pb.autoCancellation(true)
|
|
```
|
|
|
|
### Rate Limiting
|
|
PocketBase includes built-in rate limiting. For custom rate limiting, add it in your application logic or use a reverse proxy.
|
|
|
|
## Best Practices
|
|
|
|
1. **Always use HTTPS in production**
|
|
2. **Validate data on both client and server**
|
|
3. **Use proper CORS configuration**
|
|
4. **Implement row-level security rules**
|
|
5. **Use pagination for large datasets**
|
|
6. **Cache frequent queries on the client**
|
|
7. **Unsubscribe from real-time events when no longer needed**
|
|
8. **Use file size and type validation**
|
|
9. **Implement proper error boundaries**
|
|
10. **Log security events and authentication failures**
|