Skip to content

Commit adaa69f

Browse files
authored
Merge pull request #76 from objectstack-ai/copilot/update-api-routing-logic
2 parents 9fab9a2 + 9cda3ad commit adaa69f

File tree

12 files changed

+1004
-77
lines changed

12 files changed

+1004
-77
lines changed

docs/api/custom-routes.md

Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
# Custom API Routes Configuration
2+
3+
## Overview
4+
5+
ObjectQL allows you to configure custom API route paths during initialization instead of using hardcoded default paths. This feature provides flexibility for:
6+
7+
- **API Versioning**: Use paths like `/v1/api`, `/v2/api`
8+
- **Custom Naming**: Use domain-specific naming like `/resources`, `/schema`
9+
- **Multiple API Instances**: Run multiple ObjectQL instances with different paths
10+
- **Integration Requirements**: Align with existing API structures
11+
12+
## Default Routes
13+
14+
By default, ObjectQL uses these API paths:
15+
16+
| Endpoint Type | Default Path | Description |
17+
|--------------|--------------|-------------|
18+
| JSON-RPC | `/api/objectql` | Remote procedure calls |
19+
| REST Data API | `/api/data` | CRUD operations on objects |
20+
| Metadata API | `/api/metadata` | Schema and metadata information |
21+
| File Operations | `/api/files` | File upload and download |
22+
23+
## Configuration
24+
25+
### Basic Usage
26+
27+
Configure custom routes when creating handlers:
28+
29+
```typescript
30+
import { createNodeHandler, createRESTHandler, createMetadataHandler } from '@objectql/server';
31+
32+
// Define custom routes
33+
const customRoutes = {
34+
rpc: '/v1/rpc',
35+
data: '/v1/resources',
36+
metadata: '/v1/schema',
37+
files: '/v1/storage'
38+
};
39+
40+
// Create handlers with custom routes
41+
const nodeHandler = createNodeHandler(app, { routes: customRoutes });
42+
const restHandler = createRESTHandler(app, { routes: customRoutes });
43+
const metadataHandler = createMetadataHandler(app, { routes: customRoutes });
44+
```
45+
46+
### Route Configuration Interface
47+
48+
```typescript
49+
interface ApiRouteConfig {
50+
/**
51+
* Base path for JSON-RPC endpoint
52+
* @default '/api/objectql'
53+
*/
54+
rpc?: string;
55+
56+
/**
57+
* Base path for REST data API
58+
* @default '/api/data'
59+
*/
60+
data?: string;
61+
62+
/**
63+
* Base path for metadata API
64+
* @default '/api/metadata'
65+
*/
66+
metadata?: string;
67+
68+
/**
69+
* Base path for file operations
70+
* @default '/api/files'
71+
*/
72+
files?: string;
73+
}
74+
```
75+
76+
## Complete Example
77+
78+
```typescript
79+
import express from 'express';
80+
import { ObjectQL } from '@objectql/core';
81+
import { SqlDriver } from '@objectql/driver-sql';
82+
import { createNodeHandler, createRESTHandler, createMetadataHandler } from '@objectql/server';
83+
84+
async function main() {
85+
// 1. Initialize ObjectQL
86+
const app = new ObjectQL({
87+
datasources: {
88+
default: new SqlDriver({
89+
client: 'sqlite3',
90+
connection: { filename: ':memory:' },
91+
useNullAsDefault: true
92+
})
93+
}
94+
});
95+
96+
// Register your objects
97+
app.registerObject({
98+
name: 'user',
99+
label: 'User',
100+
fields: {
101+
name: { type: 'text', label: 'Name' },
102+
email: { type: 'email', label: 'Email' }
103+
}
104+
});
105+
106+
await app.init();
107+
108+
// 2. Define custom API routes
109+
const customRoutes = {
110+
rpc: '/v1/rpc',
111+
data: '/v1/resources',
112+
metadata: '/v1/schema',
113+
files: '/v1/storage'
114+
};
115+
116+
// 3. Create handlers with custom routes
117+
const nodeHandler = createNodeHandler(app, { routes: customRoutes });
118+
const restHandler = createRESTHandler(app, { routes: customRoutes });
119+
const metadataHandler = createMetadataHandler(app, { routes: customRoutes });
120+
121+
// 4. Setup Express with custom paths
122+
const server = express();
123+
124+
server.all('/v1/rpc*', nodeHandler);
125+
server.all('/v1/resources/*', restHandler);
126+
server.all('/v1/schema*', metadataHandler);
127+
128+
server.listen(3000, () => {
129+
console.log('🚀 Server running with custom routes');
130+
console.log(' JSON-RPC: http://localhost:3000/v1/rpc');
131+
console.log(' REST API: http://localhost:3000/v1/resources');
132+
console.log(' Metadata: http://localhost:3000/v1/schema');
133+
console.log(' Files: http://localhost:3000/v1/storage');
134+
});
135+
}
136+
137+
main().catch(console.error);
138+
```
139+
140+
## Using Custom Routes
141+
142+
### JSON-RPC Endpoint
143+
144+
**Default:** `POST /api/objectql`
145+
**Custom:** `POST /v1/rpc`
146+
147+
```bash
148+
curl -X POST http://localhost:3000/v1/rpc \
149+
-H "Content-Type: application/json" \
150+
-d '{
151+
"op": "find",
152+
"object": "user",
153+
"args": {}
154+
}'
155+
```
156+
157+
### REST Data API
158+
159+
**Default:** `/api/data/:object`
160+
**Custom:** `/v1/resources/:object`
161+
162+
```bash
163+
# List users
164+
curl http://localhost:3000/v1/resources/user
165+
166+
# Get specific user
167+
curl http://localhost:3000/v1/resources/user/123
168+
169+
# Create user
170+
curl -X POST http://localhost:3000/v1/resources/user \
171+
-H "Content-Type: application/json" \
172+
-d '{"name": "Alice", "email": "alice@example.com"}'
173+
174+
# Update user
175+
curl -X PUT http://localhost:3000/v1/resources/user/123 \
176+
-H "Content-Type: application/json" \
177+
-d '{"name": "Alice Updated"}'
178+
179+
# Delete user
180+
curl -X DELETE http://localhost:3000/v1/resources/user/123
181+
```
182+
183+
### Metadata API
184+
185+
**Default:** `/api/metadata`
186+
**Custom:** `/v1/schema`
187+
188+
```bash
189+
# List all objects
190+
curl http://localhost:3000/v1/schema/objects
191+
192+
# Get object details
193+
curl http://localhost:3000/v1/schema/object/user
194+
195+
# Get field metadata
196+
curl http://localhost:3000/v1/schema/object/user/fields/email
197+
198+
# List object actions
199+
curl http://localhost:3000/v1/schema/object/user/actions
200+
```
201+
202+
### File Operations
203+
204+
**Default:** `/api/files`
205+
**Custom:** `/v1/storage`
206+
207+
```bash
208+
# Upload file
209+
curl -X POST http://localhost:3000/v1/storage/upload \
210+
-F "file=@myfile.pdf" \
211+
-F "object=document" \
212+
-F "field=attachment"
213+
214+
# Download file
215+
curl http://localhost:3000/v1/storage/abc123
216+
```
217+
218+
## Client SDK Configuration
219+
220+
The ObjectQL SDK clients also support custom route configuration:
221+
222+
### Data API Client
223+
224+
```typescript
225+
import { DataApiClient } from '@objectql/sdk';
226+
227+
const client = new DataApiClient({
228+
baseUrl: 'http://localhost:3000',
229+
dataPath: '/v1/resources' // Custom data path
230+
});
231+
232+
const users = await client.list('user');
233+
```
234+
235+
### Metadata API Client
236+
237+
```typescript
238+
import { MetadataApiClient } from '@objectql/sdk';
239+
240+
const client = new MetadataApiClient({
241+
baseUrl: 'http://localhost:3000',
242+
metadataPath: '/v1/schema' // Custom metadata path
243+
});
244+
245+
const objects = await client.listObjects();
246+
```
247+
248+
### Remote Driver
249+
250+
```typescript
251+
import { RemoteDriver } from '@objectql/sdk';
252+
253+
const driver = new RemoteDriver(
254+
'http://localhost:3000',
255+
'/v1/rpc' // Custom RPC path
256+
);
257+
```
258+
259+
## Common Use Cases
260+
261+
### API Versioning
262+
263+
Support multiple API versions simultaneously:
264+
265+
```typescript
266+
// API v1
267+
const v1Routes = {
268+
rpc: '/api/v1/rpc',
269+
data: '/api/v1/data',
270+
metadata: '/api/v1/metadata',
271+
files: '/api/v1/files'
272+
};
273+
274+
// API v2
275+
const v2Routes = {
276+
rpc: '/api/v2/rpc',
277+
data: '/api/v2/data',
278+
metadata: '/api/v2/metadata',
279+
files: '/api/v2/files'
280+
};
281+
282+
const v1Handler = createNodeHandler(appV1, { routes: v1Routes });
283+
const v2Handler = createNodeHandler(appV2, { routes: v2Routes });
284+
285+
server.all('/api/v1/*', v1Handler);
286+
server.all('/api/v2/*', v2Handler);
287+
```
288+
289+
### Domain-Specific Naming
290+
291+
Use business-friendly terminology:
292+
293+
```typescript
294+
const businessRoutes = {
295+
rpc: '/business/operations',
296+
data: '/business/entities',
297+
metadata: '/business/definitions',
298+
files: '/business/documents'
299+
};
300+
```
301+
302+
### Multi-Tenant Applications
303+
304+
Isolate APIs per tenant:
305+
306+
```typescript
307+
app.use('/:tenantId/api/*', (req, res, next) => {
308+
const tenantRoutes = {
309+
rpc: `/${req.params.tenantId}/api/rpc`,
310+
data: `/${req.params.tenantId}/api/data`,
311+
metadata: `/${req.params.tenantId}/api/metadata`,
312+
files: `/${req.params.tenantId}/api/files`
313+
};
314+
315+
const handler = createNodeHandler(
316+
getTenantApp(req.params.tenantId),
317+
{ routes: tenantRoutes }
318+
);
319+
320+
handler(req, res);
321+
});
322+
```
323+
324+
## Backward Compatibility
325+
326+
All handlers maintain backward compatibility:
327+
328+
- If no `routes` option is provided, default paths are used
329+
- Existing applications continue to work without changes
330+
- Migration to custom routes is opt-in
331+
332+
```typescript
333+
// This still works with default routes
334+
const handler = createNodeHandler(app);
335+
// Uses /api/objectql, /api/data, /api/metadata, /api/files
336+
```
337+
338+
## Best Practices
339+
340+
1. **Consistency**: Use the same route structure across all handlers
341+
2. **Documentation**: Document your custom routes for API consumers
342+
3. **Versioning**: Consider using versioned paths for production APIs
343+
4. **Testing**: Test custom routes thoroughly before deployment
344+
5. **Migration**: Plan gradual migration if changing existing routes
345+
346+
## Related Documentation
347+
348+
- [REST API Reference](./rest.md)
349+
- [JSON-RPC API Reference](./json-rpc.md)
350+
- [Metadata API Reference](./metadata.md)
351+
- [Client SDK Guide](./client-sdk.md)

docs/api/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ ObjectQL uses a **unified `id` field** as the primary key across all database dr
3232
## Quick Links
3333

3434
### Core Concepts
35+
- [Custom API Routes](./custom-routes.md)**NEW**
3536
- [Authentication & Security](./authentication.md)
3637
- [Error Handling](./error-handling.md)
3738
- [Rate Limiting](./rate-limiting.md)

0 commit comments

Comments
 (0)