Initial commit
This commit is contained in:
396
skills/pocketbase/references/api_reference.md
Normal file
396
skills/pocketbase/references/api_reference.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# 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**
|
||||
Reference in New Issue
Block a user