Skip to content

Commit 0ea579f

Browse files
committed
Add Express server example and CLI serve command
Introduces a new Express server example with ObjectQL integration, including schema and configuration files. Adds a 'serve' command to the CLI for starting a development server with in-memory SQLite, updates dependencies, and registers the new command in the CLI entry point.
1 parent caaff6e commit 0ea579f

7 files changed

Lines changed: 144 additions & 58 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@example/express-server",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "tsc && cp src/*.yml dist/ || true",
7+
"start": "node dist/index.js"
8+
},
9+
"dependencies": {
10+
"@objectql/core": "workspace:*",
11+
"@objectql/server": "workspace:*",
12+
"@objectql/types": "workspace:*",
13+
"@objectql/driver-knex": "workspace:*",
14+
"express": "^4.18.2",
15+
"sqlite3": "^5.1.7"
16+
},
17+
"devDependencies": {
18+
"@types/express": "^4.17.21",
19+
"typescript": "^5.0.0"
20+
}
21+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import express from 'express';
2+
import { ObjectQL } from '@objectql/core';
3+
import { KnexDriver } from '@objectql/driver-knex';
4+
import { createNodeHandler } from '@objectql/server';
5+
import * as path from 'path';
6+
7+
async function main() {
8+
// 1. Init ObjectQL
9+
const app = new ObjectQL({
10+
datasources: {
11+
default: new KnexDriver({
12+
client: 'sqlite3',
13+
connection: {
14+
filename: ':memory:'
15+
},
16+
useNullAsDefault: true
17+
})
18+
}
19+
});
20+
21+
// 2. Register Schema
22+
app.loadFromDirectory(path.join(__dirname));
23+
await app.init();
24+
25+
// 3. Create Handler
26+
const objectQLHandler = createNodeHandler(app);
27+
28+
// 4. Setup Express
29+
const server = express();
30+
const port = 3004;
31+
32+
// Optional: Parse JSON body globally (or strict to other routes)
33+
// server.use(express.json());
34+
35+
// Mount ObjectQL handler
36+
// Supports both /api/objectql (POST) or similar
37+
server.all('/api/objectql', objectQLHandler);
38+
39+
server.listen(port, () => {
40+
console.log(`Express app listening on port ${port}`);
41+
console.log(`Test CURL:`);
42+
console.log(`curl -X POST http://localhost:${port}/api/objectql -H "Content-Type: application/json" -d '{"op": "create", "object": "User", "args": { "data": { "name": "ExpressUser", "email": "express@example.com" }}}'`);
43+
});
44+
}
45+
46+
main().catch(console.error);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: User
2+
fields:
3+
name:
4+
type: string
5+
email:
6+
type: string

packages/cli/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
"dependencies": {
1313
"@objectql/types": "workspace:*",
1414
"@objectql/core": "workspace:*",
15+
"@objectql/server": "workspace:*",
16+
"@objectql/driver-knex": "workspace:*",
17+
"sqlite3": "^5.1.7",
1518
"commander": "^11.0.0",
1619
"chalk": "^4.1.2",
1720
"fast-glob": "^3.3.0",

packages/cli/src/commands/serve.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ObjectQL } from '@objectql/core';
2+
import { KnexDriver } from '@objectql/driver-knex';
3+
import { createNodeHandler } from '@objectql/server';
4+
import { createServer } from 'http';
5+
import * as path from 'path';
6+
import chalk from 'chalk';
7+
8+
export async function serve(options: { port: number; dir: string }) {
9+
console.log(chalk.blue('Starting ObjectQL Dev Server...'));
10+
11+
const rootDir = path.resolve(process.cwd(), options.dir);
12+
console.log(chalk.gray(`Loading schema from: ${rootDir}`));
13+
14+
// 1. Init ObjectQL with in-memory SQLite for Dev
15+
const app = new ObjectQL({
16+
datasources: {
17+
default: new KnexDriver({
18+
client: 'sqlite3',
19+
connection: {
20+
filename: ':memory:' // Or local file './dev.db'
21+
},
22+
useNullAsDefault: true
23+
})
24+
}
25+
});
26+
27+
// 2. Load Schema
28+
try {
29+
app.loadFromDirectory(rootDir);
30+
await app.init();
31+
console.log(chalk.green('✅ Schema loaded successfully.'));
32+
} catch (e: any) {
33+
console.error(chalk.red('❌ Failed to load schema:'), e.message);
34+
process.exit(1);
35+
}
36+
37+
// 3. Create Handler
38+
const handler = createNodeHandler(app);
39+
40+
// 4. Start Server
41+
const server = createServer(handler);
42+
43+
server.listen(options.port, () => {
44+
console.log(chalk.green(`\n🚀 Server ready at http://localhost:${options.port}`));
45+
console.log(chalk.gray('\nTry a curl command:'));
46+
console.log(`curl -X POST http://localhost:${options.port} -H "Content-Type: application/json" -d '{"op": "find", "object": "YourObject", "args": {}}'`);
47+
});
48+
}

packages/cli/src/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Command } from 'commander';
22
import { generateTypes } from './commands/generate';
33
import { startRepl } from './commands/repl';
4+
import { serve } from './commands/serve';
45

56
const program = new Command();
67

@@ -33,4 +34,14 @@ program
3334
await startRepl(options.config);
3435
});
3536

37+
program
38+
.command('serve')
39+
.alias('s')
40+
.description('Start a development server')
41+
.option('-p, --port <number>', 'Port to listen on', '3000')
42+
.option('-d, --dir <path>', 'Directory containing schema', '.')
43+
.action(async (options) => {
44+
await serve({ port: parseInt(options.port), dir: options.dir });
45+
});
46+
3647
program.parse();

pnpm-lock.yaml

Lines changed: 9 additions & 58 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)