@rebasepro/cli 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/commands/api-keys.d.ts +1 -0
- package/dist/commands/generate_sdk.d.ts +1 -1
- package/dist/commands/init.d.ts +13 -0
- package/dist/index.es.js +463 -105
- package/dist/index.es.js.map +1 -1
- package/package.json +22 -18
- package/templates/template/backend/package.json +0 -1
- package/templates/template/backend/src/index.ts +1 -1
- package/templates/template/config/collections/posts.ts +1 -3
- package/templates/template/config/collections/tags.ts +1 -3
- package/templates/template/config/collections/users.ts +1 -4
- package/templates/template/package.json +0 -1
- package/templates/template/scripts/example.ts +4 -1
- package/dist/index.cjs +0 -1948
- package/dist/index.cjs.map +0 -1
- package/skills/rebase-api/SKILL.md +0 -662
- package/skills/rebase-api/references/.gitkeep +0 -3
- package/skills/rebase-auth/SKILL.md +0 -1143
- package/skills/rebase-auth/references/.gitkeep +0 -3
- package/skills/rebase-backend-postgres/SKILL.md +0 -633
- package/skills/rebase-backend-postgres/references/.gitkeep +0 -3
- package/skills/rebase-basics/SKILL.md +0 -749
- package/skills/rebase-basics/references/.gitkeep +0 -3
- package/skills/rebase-collections/SKILL.md +0 -1328
- package/skills/rebase-collections/references/.gitkeep +0 -3
- package/skills/rebase-cron-jobs/SKILL.md +0 -699
- package/skills/rebase-cron-jobs/references/.gitkeep +0 -1
- package/skills/rebase-custom-functions/SKILL.md +0 -233
- package/skills/rebase-deployment/SKILL.md +0 -583
- package/skills/rebase-deployment/references/.gitkeep +0 -3
- package/skills/rebase-design-language/SKILL.md +0 -664
- package/skills/rebase-email/SKILL.md +0 -701
- package/skills/rebase-email/references/.gitkeep +0 -1
- package/skills/rebase-entity-history/SKILL.md +0 -485
- package/skills/rebase-entity-history/references/.gitkeep +0 -1
- package/skills/rebase-local-env-setup/SKILL.md +0 -189
- package/skills/rebase-local-env-setup/references/.gitkeep +0 -3
- package/skills/rebase-realtime/SKILL.md +0 -755
- package/skills/rebase-realtime/references/.gitkeep +0 -3
- package/skills/rebase-sdk/SKILL.md +0 -594
- package/skills/rebase-sdk/references/.gitkeep +0 -0
- package/skills/rebase-storage/SKILL.md +0 -765
- package/skills/rebase-storage/references/.gitkeep +0 -3
- package/skills/rebase-studio/SKILL.md +0 -746
- package/skills/rebase-studio/references/.gitkeep +0 -3
- package/skills/rebase-ui-components/SKILL.md +0 -1411
- package/skills/rebase-ui-components/references/.gitkeep +0 -3
- package/skills/rebase-webhooks/SKILL.md +0 -623
- package/skills/rebase-webhooks/references/.gitkeep +0 -1
- package/templates/template/backend/drizzle.config.ts +0 -51
|
@@ -1,662 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: rebase-api
|
|
3
|
-
description: Guide for working with Rebase auto-generated REST and GraphQL APIs. Use this skill when the user needs to understand the API endpoints, query parameters, filtering, sorting, pagination, or GraphQL schema.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Rebase Auto-Generated APIs
|
|
7
|
-
|
|
8
|
-
> **WARNING FOR AGENTS**: If you are writing a script or data task, **default to using the Rebase SDK** (`@rebasepro/client` or `@rebasepro/server-core`) instead of making raw REST or GraphQL API calls (`fetch` / `curl`). For custom backend functions, use `client.functions.invoke('function-name', payload)` — **NEVER** manually construct `/api/functions/` URLs or extract tokens from localStorage. Only use raw API calls if specifically instructed to do so or if you are demonstrating HTTP usage to the user.
|
|
9
|
-
|
|
10
|
-
Every collection defined in Rebase automatically gets full REST CRUD and GraphQL endpoints. No manual route creation needed.
|
|
11
|
-
|
|
12
|
-
## REST API
|
|
13
|
-
|
|
14
|
-
### Base Paths
|
|
15
|
-
|
|
16
|
-
All data routes are mounted under `/api/data/`. Other route categories:
|
|
17
|
-
|
|
18
|
-
| Base Path | Purpose |
|
|
19
|
-
|-----------|---------|
|
|
20
|
-
| `/api/data/{slug}` | Collection CRUD (auto-generated) |
|
|
21
|
-
| `/api/data/{slug}/count` | Count matching entities |
|
|
22
|
-
| `/api/data/{parent}/{parentId}/{child}` | Subcollection routes |
|
|
23
|
-
| `/api/auth/*` | Authentication (login, register, refresh, OAuth) |
|
|
24
|
-
| `/api/admin/*` | User & role management |
|
|
25
|
-
| `/api/admin/api-keys` | Service API key management |
|
|
26
|
-
| `/api/storage/*` | File uploads and downloads |
|
|
27
|
-
| `/api/functions/{name}` | Custom backend functions |
|
|
28
|
-
| `/api/schema-editor/*` | Visual schema editor (dev only) |
|
|
29
|
-
| `/api/docs` | OpenAPI 3.0.3 JSON spec |
|
|
30
|
-
| `/api/swagger` | Swagger UI (dev only) |
|
|
31
|
-
| `/api/graphql` | GraphQL endpoint (when enabled) |
|
|
32
|
-
| `/api/graphiql` | GraphiQL IDE (dev only, when GraphQL enabled) |
|
|
33
|
-
| `/api/health` | Health check (when using `RebaseApiServer`) |
|
|
34
|
-
| `/api/collections` | Collections metadata (when using `RebaseApiServer`) |
|
|
35
|
-
|
|
36
|
-
### CRUD Operations
|
|
37
|
-
|
|
38
|
-
> **IMPORTANT FOR AGENTS:** There is NO `PATCH` method. Updates use `PUT` only. `POST` returns `201`, `DELETE` returns `204` (empty body).
|
|
39
|
-
|
|
40
|
-
| Method | Endpoint | Description | Status |
|
|
41
|
-
|--------|----------|-------------|--------|
|
|
42
|
-
| `GET` | `/api/data/{slug}` | List entities (with filtering, sorting, pagination) | `200` |
|
|
43
|
-
| `GET` | `/api/data/{slug}/count` | Count matching entities (with optional filters) | `200` |
|
|
44
|
-
| `GET` | `/api/data/{slug}/:id` | Get a single entity by ID | `200` |
|
|
45
|
-
| `POST` | `/api/data/{slug}` | Create a new entity | `201` |
|
|
46
|
-
| `PUT` | `/api/data/{slug}/:id` | Update an entity | `200` |
|
|
47
|
-
| `DELETE` | `/api/data/{slug}/:id` | Delete an entity | `204` |
|
|
48
|
-
|
|
49
|
-
### Subcollection Routes
|
|
50
|
-
|
|
51
|
-
For collections with relations, Rebase generates nested routes automatically. The URL pattern is `/{parent}/{parentId}/{child}`, and it supports arbitrarily deep nesting (parent/id/child/id/grandchild):
|
|
52
|
-
|
|
53
|
-
| Method | Endpoint | Description | Status |
|
|
54
|
-
|--------|----------|-------------|--------|
|
|
55
|
-
| `GET` | `/api/data/{parent}/{parentId}/{child}` | List child entities | `200` |
|
|
56
|
-
| `GET` | `/api/data/{parent}/{parentId}/{child}/count` | Count child entities | `200` |
|
|
57
|
-
| `GET` | `/api/data/{parent}/{parentId}/{child}/:id` | Get a single child entity | `200` |
|
|
58
|
-
| `POST` | `/api/data/{parent}/{parentId}/{child}` | Create a child entity | `201` |
|
|
59
|
-
| `PUT` | `/api/data/{parent}/{parentId}/{child}/:id` | Update a child entity | `200` |
|
|
60
|
-
| `DELETE` | `/api/data/{parent}/{parentId}/{child}/:id` | Delete a child entity | `204` |
|
|
61
|
-
|
|
62
|
-
**Example:** List all posts by author `111094`:
|
|
63
|
-
```bash
|
|
64
|
-
GET /api/data/authors/111094/posts
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Query Parameters
|
|
68
|
-
|
|
69
|
-
### Pagination
|
|
70
|
-
|
|
71
|
-
| Parameter | Type | Default | Description |
|
|
72
|
-
|-----------|------|---------|-------------|
|
|
73
|
-
| `limit` | integer | `20` | Max results per page (max: `100`) |
|
|
74
|
-
| `offset` | integer | `0` | Number of records to skip |
|
|
75
|
-
| `page` | integer | — | Page number (alternative to offset). Calculates offset as `(page - 1) * limit` |
|
|
76
|
-
|
|
77
|
-
> **IMPORTANT FOR AGENTS:** The default limit is **20**, NOT 25. The max limit is **100**.
|
|
78
|
-
|
|
79
|
-
### Sorting
|
|
80
|
-
|
|
81
|
-
Use the `orderBy` parameter. Two formats are supported:
|
|
82
|
-
|
|
83
|
-
**Simple format:**
|
|
84
|
-
```
|
|
85
|
-
?orderBy=field:direction
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**JSON array format (for multi-column sort):**
|
|
89
|
-
```
|
|
90
|
-
?orderBy=[{"field":"created_at","direction":"desc"},{"field":"name","direction":"asc"}]
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
| Parameter | Type | Description | Example |
|
|
94
|
-
|-----------|------|-------------|---------|
|
|
95
|
-
| `orderBy` | string | Sort field and direction | `?orderBy=created_at:desc` |
|
|
96
|
-
|
|
97
|
-
### Filtering (PostgREST-Style)
|
|
98
|
-
|
|
99
|
-
> **IMPORTANT FOR AGENTS:** Filters use PostgREST-style syntax: `?field=op.value`. This is NOT bracket syntax. For example: `?status=eq.active`, NOT `?filter[status][eq]=active`.
|
|
100
|
-
|
|
101
|
-
Every field in the collection can be used as a query parameter with an operator prefix:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
?{field}={operator}.{value}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**Implicit equality:** A plain value without an operator prefix implies equality:
|
|
108
|
-
```
|
|
109
|
-
?status=active → status == "active"
|
|
110
|
-
?price=29.99 → price == 29.99
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Filter Operators
|
|
114
|
-
|
|
115
|
-
| Operator | Mapped To | Description | Example |
|
|
116
|
-
|----------|-----------|-------------|---------|
|
|
117
|
-
| `eq` | `==` | Equal | `?status=eq.active` |
|
|
118
|
-
| `neq` | `!=` | Not equal | `?status=neq.archived` |
|
|
119
|
-
| `gt` | `>` | Greater than | `?price=gt.50` |
|
|
120
|
-
| `gte` | `>=` | Greater than or equal | `?price=gte.50` |
|
|
121
|
-
| `lt` | `<` | Less than | `?price=lt.100` |
|
|
122
|
-
| `lte` | `<=` | Less than or equal | `?price=lte.100` |
|
|
123
|
-
| `in` | `in` | Value in list | `?status=in.(active,published)` |
|
|
124
|
-
| `nin` | `not-in` | Value not in list | `?status=nin.(archived,deleted)` |
|
|
125
|
-
| `cs` | `array-contains` | Array contains value | `?tags=cs.javascript` |
|
|
126
|
-
| `csa` | `array-contains-any` | Array contains any of values | `?tags=csa.(javascript,typescript)` |
|
|
127
|
-
|
|
128
|
-
> **WARNING FOR AGENTS:** There is NO `like` operator. Use `searchString` for text search instead.
|
|
129
|
-
|
|
130
|
-
**Array values** for `in`, `nin`, and `csa` use parenthesized comma-separated lists: `(val1,val2,val3)`.
|
|
131
|
-
|
|
132
|
-
**Automatic type coercion:** The values `true`, `false`, `null`, and numeric strings are automatically parsed to their corresponding types.
|
|
133
|
-
|
|
134
|
-
### Logical Operators (or / and)
|
|
135
|
-
|
|
136
|
-
For complex conditions, use the `or` and `and` query parameters with nested condition strings:
|
|
137
|
-
|
|
138
|
-
```
|
|
139
|
-
?or=(status.eq.active,status.eq.pending)
|
|
140
|
-
?and=(price.gte.10,price.lte.100)
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Nested logical conditions are also supported:
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
?or=(status.eq.active,and(price.gte.10,price.lte.50))
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Full-Text Search
|
|
150
|
-
|
|
151
|
-
| Parameter | Type | Description |
|
|
152
|
-
|-----------|------|-------------|
|
|
153
|
-
| `searchString` | string | Full-text search query across searchable fields |
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
?searchString=widget
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Relation Includes (Eager Loading)
|
|
160
|
-
|
|
161
|
-
| Parameter | Type | Description | Example |
|
|
162
|
-
|-----------|------|-------------|---------|
|
|
163
|
-
| `include` | string | Comma-separated list of relations to eager-load | `?include=author,tags` |
|
|
164
|
-
|
|
165
|
-
Use `*` to include all relations:
|
|
166
|
-
```
|
|
167
|
-
?include=*
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Field Selection
|
|
171
|
-
|
|
172
|
-
| Parameter | Type | Description | Example |
|
|
173
|
-
|-----------|------|-------------|---------|
|
|
174
|
-
| `fields` | string | Comma-separated list of fields to return | `?fields=id,name,price` |
|
|
175
|
-
|
|
176
|
-
### Vector Similarity Search
|
|
177
|
-
|
|
178
|
-
| Parameter | Type | Description | Example |
|
|
179
|
-
|-----------|------|-------------|---------|
|
|
180
|
-
| `vector_search` | string | Name of the vector property to search | `?vector_search=embedding` |
|
|
181
|
-
| `vector` | string | JSON array of numbers (query vector) | `?vector=[0.1,0.2,0.3]` |
|
|
182
|
-
| `vector_distance` | string | Distance function: `cosine`, `l2`, or `inner_product` (default: `cosine`) | `?vector_distance=cosine` |
|
|
183
|
-
| `vector_threshold` | number | Optional similarity threshold | `?vector_threshold=0.8` |
|
|
184
|
-
|
|
185
|
-
**Example — vector similarity search:**
|
|
186
|
-
```
|
|
187
|
-
?vector_search=embedding&vector=[0.1,0.2,0.3,0.4]&vector_distance=cosine&vector_threshold=0.5
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Reserved Query Keys
|
|
191
|
-
|
|
192
|
-
These parameter names are reserved and will NOT be interpreted as filter fields:
|
|
193
|
-
|
|
194
|
-
`limit`, `offset`, `page`, `orderBy`, `include`, `fields`, `searchString`, `vector_search`, `vector`, `vector_distance`, `vector_threshold`, `or`, `and`
|
|
195
|
-
|
|
196
|
-
## Response Format
|
|
197
|
-
|
|
198
|
-
### List Response (GET collection)
|
|
199
|
-
|
|
200
|
-
```json
|
|
201
|
-
{
|
|
202
|
-
"data": [
|
|
203
|
-
{ "id": "uuid-1", "name": "Product A", "price": 29.99 },
|
|
204
|
-
{ "id": "uuid-2", "name": "Product B", "price": 49.99 }
|
|
205
|
-
],
|
|
206
|
-
"meta": {
|
|
207
|
-
"total": 150,
|
|
208
|
-
"limit": 20,
|
|
209
|
-
"offset": 0,
|
|
210
|
-
"hasMore": true
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
> **IMPORTANT FOR AGENTS:** The pagination envelope key is `meta`, NOT `pagination`.
|
|
216
|
-
|
|
217
|
-
### Single Entity Response (GET by ID)
|
|
218
|
-
|
|
219
|
-
Returns the flat entity object directly (no `data` wrapper):
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"id": "uuid-1",
|
|
224
|
-
"name": "Product A",
|
|
225
|
-
"price": 29.99,
|
|
226
|
-
"created_at": "2025-01-15T10:30:00.000Z"
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### Create Response (POST — 201)
|
|
231
|
-
|
|
232
|
-
Returns the created entity as a flat object:
|
|
233
|
-
|
|
234
|
-
```json
|
|
235
|
-
{
|
|
236
|
-
"id": "generated-uuid",
|
|
237
|
-
"name": "New Product",
|
|
238
|
-
"price": 19.99
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Update Response (PUT — 200)
|
|
243
|
-
|
|
244
|
-
Returns the updated entity as a flat object.
|
|
245
|
-
|
|
246
|
-
### Delete Response (DELETE — 204)
|
|
247
|
-
|
|
248
|
-
Returns an empty body with status `204 No Content`.
|
|
249
|
-
|
|
250
|
-
### Count Response
|
|
251
|
-
|
|
252
|
-
```json
|
|
253
|
-
{
|
|
254
|
-
"count": 42
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Error Handling
|
|
259
|
-
|
|
260
|
-
All errors follow the canonical shape:
|
|
261
|
-
|
|
262
|
-
```json
|
|
263
|
-
{
|
|
264
|
-
"error": {
|
|
265
|
-
"message": "Human-readable error description",
|
|
266
|
-
"code": "ERROR_CODE",
|
|
267
|
-
"details": {}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
The `details` field is optional and only present when additional context is available.
|
|
273
|
-
|
|
274
|
-
### Error Codes and HTTP Status Codes
|
|
275
|
-
|
|
276
|
-
| HTTP Status | Code | Description |
|
|
277
|
-
|-------------|------|-------------|
|
|
278
|
-
| `400` | `BAD_REQUEST` | Invalid input or malformed request |
|
|
279
|
-
| `400` | `INVALID_INPUT` | Validation failure |
|
|
280
|
-
| `401` | `UNAUTHORIZED` | Missing or invalid authentication token |
|
|
281
|
-
| `401` | `INVALID_CREDENTIALS` | Wrong email/password |
|
|
282
|
-
| `401` | `INVALID_TOKEN` | Expired or malformed JWT |
|
|
283
|
-
| `403` | `FORBIDDEN` | Insufficient permissions (e.g., API key lacks permission) |
|
|
284
|
-
| `403` | `API_KEY_FORBIDDEN` | API key does not have permission for this operation |
|
|
285
|
-
| `404` | `NOT_FOUND` | Entity not found |
|
|
286
|
-
| `409` | `CONFLICT` | Duplicate resource (e.g., email exists) |
|
|
287
|
-
| `409` | `EMAIL_EXISTS` | Registration with existing email |
|
|
288
|
-
| `413` | `PAYLOAD_TOO_LARGE` | Request body exceeds max size (default 10MB) |
|
|
289
|
-
| `500` | `INTERNAL_ERROR` | Unexpected server error |
|
|
290
|
-
| `503` | `SERVICE_UNAVAILABLE` | Service not available |
|
|
291
|
-
|
|
292
|
-
### ApiError Factory Methods
|
|
293
|
-
|
|
294
|
-
The backend uses `ApiError` static methods to throw typed errors:
|
|
295
|
-
|
|
296
|
-
```typescript
|
|
297
|
-
ApiError.badRequest("Invalid email format", "INVALID_INPUT");
|
|
298
|
-
ApiError.unauthorized("Token expired");
|
|
299
|
-
ApiError.forbidden("Admin access required");
|
|
300
|
-
ApiError.notFound("Entity not found");
|
|
301
|
-
ApiError.conflict("Email already registered", "EMAIL_EXISTS");
|
|
302
|
-
ApiError.internal("Database connection failed");
|
|
303
|
-
ApiError.serviceUnavailable("Service is down");
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
## Authentication
|
|
307
|
-
|
|
308
|
-
### Bearer Token (JWT)
|
|
309
|
-
|
|
310
|
-
```
|
|
311
|
-
Authorization: Bearer <jwt-token>
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Query Parameter Token
|
|
315
|
-
|
|
316
|
-
As an alternative to the Authorization header, pass the token as a query parameter:
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
?token=<jwt-token>
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Service Key
|
|
323
|
-
|
|
324
|
-
A static secret key for server-to-server or script authentication. When a request sends a Bearer token matching the service key, it is granted admin-level access (`userId: "service"`, `roles: ["admin"]`) without JWT verification.
|
|
325
|
-
|
|
326
|
-
```
|
|
327
|
-
Authorization: Bearer <service-key>
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### API Keys (rk_ prefix)
|
|
331
|
-
|
|
332
|
-
Service API keys start with the `rk_` prefix and are validated against the database. API keys have per-collection permissions controlling which CRUD operations are allowed:
|
|
333
|
-
|
|
334
|
-
```
|
|
335
|
-
Authorization: Bearer rk_live_abc123...
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
If an API key lacks the required permission for an operation, a `403 API_KEY_FORBIDDEN` error is returned.
|
|
339
|
-
|
|
340
|
-
### Authentication Enforcement
|
|
341
|
-
|
|
342
|
-
- **Default:** Auth is required (`requireAuth: true`). Requests without a valid token receive `401`.
|
|
343
|
-
- **Public access:** Set `requireAuth: false` to allow anonymous access. Access control is then fully delegated to Postgres Row-Level Security (RLS) policies.
|
|
344
|
-
- **Fail-closed:** The raw unscoped driver is never placed in the request context. Every request is either RLS-scoped or rejected.
|
|
345
|
-
|
|
346
|
-
## DataHooks Lifecycle
|
|
347
|
-
|
|
348
|
-
DataHooks run at the REST API boundary (after DB operations, before response) and apply to **all** collections. They are configured via `hooks.data` in the backend config.
|
|
349
|
-
|
|
350
|
-
| Hook | Trigger | Can Modify? | Can Abort? |
|
|
351
|
-
|------|---------|-------------|------------|
|
|
352
|
-
| `afterRead(slug, entity, ctx)` | GET (list & single) | Return modified entity, or `null` to filter it out | No |
|
|
353
|
-
| `beforeSave(slug, values, entityId, ctx)` | POST and PUT, before DB write | Return modified values | Throw to abort |
|
|
354
|
-
| `afterSave(slug, entity, ctx)` | POST and PUT, after DB write | No (fire-and-forget) | No |
|
|
355
|
-
| `beforeDelete(slug, entityId, ctx)` | DELETE, before DB delete | No | Throw to abort |
|
|
356
|
-
| `afterDelete(slug, entityId, ctx)` | DELETE, after DB delete | No (fire-and-forget) | No |
|
|
357
|
-
|
|
358
|
-
The `BackendHookContext` provides:
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
interface BackendHookContext {
|
|
362
|
-
requestUser?: { userId: string; roles: string[] };
|
|
363
|
-
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
> **IMPORTANT FOR AGENTS:** `afterSave` and `afterDelete` are fire-and-forget — they run asynchronously and do not block the response. Errors in these hooks are logged but not returned to the client.
|
|
368
|
-
|
|
369
|
-
**Example — masking PII for non-admin users:**
|
|
370
|
-
|
|
371
|
-
```typescript
|
|
372
|
-
const hooks: BackendHooks = {
|
|
373
|
-
data: {
|
|
374
|
-
afterRead(slug, entity, ctx) {
|
|
375
|
-
if (!ctx.requestUser?.roles.includes("admin") && entity.email) {
|
|
376
|
-
return { ...entity, email: "***" };
|
|
377
|
-
}
|
|
378
|
-
return entity;
|
|
379
|
-
},
|
|
380
|
-
beforeSave(slug, values, entityId, ctx) {
|
|
381
|
-
// Add audit trail
|
|
382
|
-
return { ...values, updatedBy: ctx.requestUser?.userId };
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
## REST API Examples
|
|
389
|
-
|
|
390
|
-
### List with filtering, sorting, and pagination
|
|
391
|
-
|
|
392
|
-
```bash
|
|
393
|
-
curl -H "Authorization: Bearer $TOKEN" \
|
|
394
|
-
"https://example.com/api/data/products?status=eq.active&price=gte.50&orderBy=created_at:desc&limit=10&offset=0&include=category"
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### Create an entity
|
|
398
|
-
|
|
399
|
-
```bash
|
|
400
|
-
curl -X POST \
|
|
401
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
402
|
-
-H "Content-Type: application/json" \
|
|
403
|
-
-d '{"name": "New Widget", "price": 19.99, "status": "draft"}' \
|
|
404
|
-
"https://example.com/api/data/products"
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### Update an entity
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
curl -X PUT \
|
|
411
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
412
|
-
-H "Content-Type: application/json" \
|
|
413
|
-
-d '{"name": "Updated Widget", "price": 24.99, "status": "active"}' \
|
|
414
|
-
"https://example.com/api/data/products/uuid-123"
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Delete an entity
|
|
418
|
-
|
|
419
|
-
```bash
|
|
420
|
-
curl -X DELETE \
|
|
421
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
422
|
-
"https://example.com/api/data/products/uuid-123"
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Count with filters
|
|
426
|
-
|
|
427
|
-
```bash
|
|
428
|
-
curl -H "Authorization: Bearer $TOKEN" \
|
|
429
|
-
"https://example.com/api/data/products/count?status=eq.active"
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
### Logical OR filtering
|
|
433
|
-
|
|
434
|
-
```bash
|
|
435
|
-
curl -H "Authorization: Bearer $TOKEN" \
|
|
436
|
-
"https://example.com/api/data/products?or=(status.eq.active,status.eq.pending)"
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
### Subcollection listing
|
|
440
|
-
|
|
441
|
-
```bash
|
|
442
|
-
curl -H "Authorization: Bearer $TOKEN" \
|
|
443
|
-
"https://example.com/api/data/authors/111094/posts?orderBy=created_at:desc&limit=5"
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
## GraphQL API
|
|
447
|
-
|
|
448
|
-
### Endpoint
|
|
449
|
-
|
|
450
|
-
```
|
|
451
|
-
POST /api/graphql
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
GraphQL is **enabled by default** (`enableGraphQL: true` in `ApiConfig`). In non-production environments, a GraphiQL IDE is also available at `/api/graphiql`.
|
|
455
|
-
|
|
456
|
-
### Auto-Generated Schema
|
|
457
|
-
|
|
458
|
-
For each collection, Rebase generates the following GraphQL types and operations:
|
|
459
|
-
|
|
460
|
-
**Types:**
|
|
461
|
-
- `{TypeName}` — Entity output type (e.g., `Product`, `BlogPost`)
|
|
462
|
-
- `{TypeName}Input` — Input type for create/update mutations
|
|
463
|
-
|
|
464
|
-
The type name is derived from `collection.singularName` (spaces removed) or by removing the last character of `collection.name`.
|
|
465
|
-
|
|
466
|
-
**Queries:**
|
|
467
|
-
|
|
468
|
-
| Query | Arguments | Returns | Description |
|
|
469
|
-
|-------|-----------|---------|-------------|
|
|
470
|
-
| `{typeName}` (lowercase) | `id: String!` | `{TypeName}` | Get single entity |
|
|
471
|
-
| `{collection.slug}` | `limit: Int = 20`, `offset: Int = 0`, `where: String`, `orderBy: String` | `[{TypeName}]` | List entities |
|
|
472
|
-
|
|
473
|
-
**Mutations:**
|
|
474
|
-
|
|
475
|
-
| Mutation | Arguments | Returns | Description |
|
|
476
|
-
|----------|-----------|---------|-------------|
|
|
477
|
-
| `create{TypeName}` | `input: {TypeName}Input!` | `{TypeName}` | Create entity |
|
|
478
|
-
| `update{TypeName}` | `id: String!`, `input: {TypeName}Input!` | `{TypeName}` | Update entity |
|
|
479
|
-
| `delete{TypeName}` | `id: String!` | `Boolean` | Delete entity (returns `true`/`false`) |
|
|
480
|
-
|
|
481
|
-
### GraphQL Type Mapping
|
|
482
|
-
|
|
483
|
-
| Rebase Property Type | GraphQL Type |
|
|
484
|
-
|---------------------|--------------|
|
|
485
|
-
| `string` | `String` |
|
|
486
|
-
| `binary` | `String` |
|
|
487
|
-
| `number` | `Float` |
|
|
488
|
-
| `boolean` | `Boolean` |
|
|
489
|
-
| `date` | `String` |
|
|
490
|
-
| `array` | `[String]` |
|
|
491
|
-
| `vector` | `[Float]` |
|
|
492
|
-
| All others | `String` |
|
|
493
|
-
|
|
494
|
-
Fields with `validation.required` are wrapped in `GraphQLNonNull`.
|
|
495
|
-
|
|
496
|
-
### GraphQL Query Examples
|
|
497
|
-
|
|
498
|
-
**List products with filters:**
|
|
499
|
-
|
|
500
|
-
```graphql
|
|
501
|
-
query {
|
|
502
|
-
products(
|
|
503
|
-
limit: 10,
|
|
504
|
-
offset: 0,
|
|
505
|
-
where: "{\"status\":[\"==\",\"active\"]}",
|
|
506
|
-
orderBy: "created_at"
|
|
507
|
-
) {
|
|
508
|
-
id
|
|
509
|
-
name
|
|
510
|
-
price
|
|
511
|
-
status
|
|
512
|
-
created_at
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
> **IMPORTANT FOR AGENTS:** The `where` argument is a JSON **string**, not an object. It must be a valid JSON object where keys are field names and values are `[operator, value]` tuples. The `orderBy` argument is a plain field name string.
|
|
518
|
-
|
|
519
|
-
**Get single product:**
|
|
520
|
-
|
|
521
|
-
```graphql
|
|
522
|
-
query {
|
|
523
|
-
product(id: "uuid-123") {
|
|
524
|
-
id
|
|
525
|
-
name
|
|
526
|
-
price
|
|
527
|
-
category
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
**Create product:**
|
|
533
|
-
|
|
534
|
-
```graphql
|
|
535
|
-
mutation {
|
|
536
|
-
createProduct(input: {
|
|
537
|
-
name: "New Widget",
|
|
538
|
-
price: 19.99,
|
|
539
|
-
status: "draft"
|
|
540
|
-
}) {
|
|
541
|
-
id
|
|
542
|
-
name
|
|
543
|
-
price
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
**Update product:**
|
|
549
|
-
|
|
550
|
-
```graphql
|
|
551
|
-
mutation {
|
|
552
|
-
updateProduct(id: "uuid-123", input: {
|
|
553
|
-
name: "Updated Widget",
|
|
554
|
-
price: 24.99
|
|
555
|
-
}) {
|
|
556
|
-
id
|
|
557
|
-
name
|
|
558
|
-
price
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
**Delete product:**
|
|
564
|
-
|
|
565
|
-
```graphql
|
|
566
|
-
mutation {
|
|
567
|
-
deleteProduct(id: "uuid-123")
|
|
568
|
-
}
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
## OpenAPI / Swagger
|
|
572
|
-
|
|
573
|
-
### OpenAPI 3.0.3 Spec
|
|
574
|
-
|
|
575
|
-
Available at `GET /api/docs`. Returns a JSON OpenAPI specification that mirrors the REST API exactly.
|
|
576
|
-
|
|
577
|
-
The spec includes:
|
|
578
|
-
- All collection CRUD routes with parameters and schemas
|
|
579
|
-
- PostgREST-style filter parameters per field
|
|
580
|
-
- Subcollection routes for relations
|
|
581
|
-
- Component schemas for each collection (output and input)
|
|
582
|
-
- `PaginationMeta` and `ErrorResponse` component schemas
|
|
583
|
-
- Security schemes (`bearerAuth` and `queryToken`) when auth is enabled
|
|
584
|
-
- Proper `201` for POST and `204` for DELETE
|
|
585
|
-
|
|
586
|
-
### Swagger UI
|
|
587
|
-
|
|
588
|
-
Available at `GET /api/swagger` in non-production environments. Renders an interactive Swagger UI that loads the spec from `/api/docs`.
|
|
589
|
-
|
|
590
|
-
## Metadata Endpoints
|
|
591
|
-
|
|
592
|
-
### Health Check (RebaseApiServer only)
|
|
593
|
-
|
|
594
|
-
```
|
|
595
|
-
GET /api/health
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
```json
|
|
599
|
-
{
|
|
600
|
-
"status": "healthy",
|
|
601
|
-
"timestamp": "2025-01-15T10:30:00.000Z",
|
|
602
|
-
"collections": ["products", "users", "orders"],
|
|
603
|
-
"driver": "postgres"
|
|
604
|
-
}
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
### Collections Metadata (RebaseApiServer only)
|
|
608
|
-
|
|
609
|
-
```
|
|
610
|
-
GET /api/collections
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
```json
|
|
614
|
-
{
|
|
615
|
-
"data": [
|
|
616
|
-
{
|
|
617
|
-
"slug": "products",
|
|
618
|
-
"name": "Products",
|
|
619
|
-
"singularName": "Product",
|
|
620
|
-
"description": "Product catalog",
|
|
621
|
-
"properties": ["name", "price", "status", "created_at"],
|
|
622
|
-
"relations": [
|
|
623
|
-
{
|
|
624
|
-
"relationName": "category",
|
|
625
|
-
"target": "categories",
|
|
626
|
-
"cardinality": "many_to_one",
|
|
627
|
-
"direction": "outbound"
|
|
628
|
-
}
|
|
629
|
-
]
|
|
630
|
-
}
|
|
631
|
-
]
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
## Server Configuration (ApiConfig)
|
|
636
|
-
|
|
637
|
-
| Option | Type | Default | Description |
|
|
638
|
-
|--------|------|---------|-------------|
|
|
639
|
-
| `basePath` | `string` | `"/api"` | Base path for all API routes |
|
|
640
|
-
| `enableGraphQL` | `boolean` | `true` | Enable GraphQL endpoint |
|
|
641
|
-
| `enableREST` | `boolean` | `true` | Enable REST CRUD endpoints |
|
|
642
|
-
| `requireAuth` | `boolean` | `true` | Require authentication for API endpoints |
|
|
643
|
-
| `pagination.defaultLimit` | `number` | `20` | Default page size |
|
|
644
|
-
| `pagination.maxLimit` | `number` | `100` | Maximum allowed page size |
|
|
645
|
-
| `cors.origin` | `string \| string[] \| boolean` | — | CORS origin configuration |
|
|
646
|
-
| `cors.credentials` | `boolean` | `false` | Allow credentials in CORS |
|
|
647
|
-
| `collections` | `EntityCollection[]` | `[]` | Collections to generate APIs for |
|
|
648
|
-
| `collectionsDir` | `string` | — | Directory to auto-discover collections |
|
|
649
|
-
|
|
650
|
-
## References
|
|
651
|
-
|
|
652
|
-
- **Documentation:** [rebase.pro/docs](https://rebase.pro/docs)
|
|
653
|
-
- **GitHub:** [github.com/rebasepro/rebase](https://github.com/rebasepro/rebase)
|
|
654
|
-
- **REST API Generator:** `packages/server-core/src/api/rest/api-generator.ts`
|
|
655
|
-
- **Query Parser:** `packages/server-core/src/api/rest/query-parser.ts`
|
|
656
|
-
- **GraphQL Generator:** `packages/server-core/src/api/graphql/graphql-schema-generator.ts`
|
|
657
|
-
- **OpenAPI Generator:** `packages/server-core/src/api/openapi-generator.ts`
|
|
658
|
-
- **Error Handling:** `packages/server-core/src/api/errors.ts`
|
|
659
|
-
- **Server Setup:** `packages/server-core/src/api/server.ts`
|
|
660
|
-
- **API Types:** `packages/server-core/src/api/types.ts`
|
|
661
|
-
- **Auth Middleware:** `packages/server-core/src/auth/middleware.ts`
|
|
662
|
-
- **DataHooks Types:** `packages/types/src/types/backend_hooks.ts`
|