README
ΒΆ
JavaScript Playground Server
A dynamic, JavaScript-powered web server built in Go that provides an Express.js compatible API for creating web applications entirely through JavaScript code - with built-in SQLite database integration and real-time endpoint registration.
π Quick Start
# Start the server
go run . serve -p 8080
# Execute JavaScript code (Express.js style)
go run . execute "app.get('/hello', (req, res) => res.send('Hello World!'))"
# Test the server
go run . test
Then visit http://localhost:8080/hello to see your endpoint in action!
β¨ Features
- Express.js Compatible API: Use familiar Express.js syntax (
app.get,app.post,req,res) - Dynamic JavaScript Runtime: Execute JavaScript code that can register HTTP endpoints in real-time
- SQLite Integration: Direct database access from JavaScript with automatic parameter binding
- Express.js Response Methods:
res.send(),res.json(),res.status(),res.redirect(), etc. - Persistent State:
globalStateobject maintains data across script executions - Hot Reloading: Modify endpoints without server restart
- Script Isolation: Safe execution with function scope wrapping
- Structured Logging: Comprehensive logging with configurable levels
- Legacy Support: Backward compatible with custom
registerHandlerAPI
π Documentation
- JavaScript Developer Guide - Complete guide to building applications in the sandboxed environment
- Server Architecture & Internals - Deep dive into how the server works internally
- Express.js API Reference - Familiar Express.js compatible API for web development
Quick Reference
The server provides a complete Express.js compatible development environment:
// Express.js style routing
app.get('/users/:id', (req, res) => {
const user = db.query('SELECT * FROM users WHERE id = ?', [req.params.id])[0];
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
// Database integration
app.post('/users', (req, res) => {
const { name, email } = req.body;
db.query('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
res.status(201).json({ message: 'User created' });
});
// Global state management
if (!globalState.appConfig) {
globalState.appConfig = { version: '1.0.0', requestCount: 0 };
}
π Examples
Simple API Endpoint (Express.js style)
app.get("/api/users", (req, res) => {
const users = db.query("SELECT * FROM users");
res.json({ users, count: users.length });
});
Dynamic HTML Page
app.get("/dashboard", (req, res) => {
const html = `
<!DOCTYPE html>
<html>
<head><title>Dashboard</title></head>
<body>
<h1>Server Status</h1>
<p>Time: ${new Date().toISOString()}</p>
<p>Requests: ${globalState.requestCount || 0}</p>
</body>
</html>`;
res.send(html);
});
Route Parameters
app.get("/users/:id", (req, res) => {
const userId = req.params.id;
const user = db.query("SELECT * FROM users WHERE id = ?", [userId])[0];
if (!user) {
return res.status(404).json({ error: "User not found" });
}
res.json(user);
});
POST Endpoint with JSON Body
app.post("/api/users", (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: "Name and email required" });
}
db.query("INSERT INTO users (name, email) VALUES (?, ?)", [name, email]);
res.status(201).json({ message: "User created successfully" });
});
Database Operations
// Create table
db.query(`CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY,
title TEXT,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`);
// Insert data
db.query("INSERT INTO posts (title, content) VALUES (?, ?)",
["Hello World", "This is my first post"]);
// Query data
const posts = db.query("SELECT * FROM posts ORDER BY created_at DESC");
π οΈ CLI Commands
Server Commands
# Start server with custom configuration
go run . serve --port 8080 --db data.sqlite --log-level info
# Load JavaScript files on startup
go run . serve --scripts ./my-scripts/
# Production mode
go run . serve --port 80 --log-level warn --db /data/production.sqlite
Client Commands
# Execute JavaScript from file
go run . execute script.js
# Execute JavaScript from command line
go run . execute "console.log('Hello from CLI')"
# Test server endpoints
go run . test --url http://localhost:8080
ποΈ Project Structure
cmd/experiments/js-web-server/
βββ main.go # CLI interface and server bootstrap
βββ internal/
β βββ engine/
β β βββ engine.go # Core JavaScript runtime (Goja)
β β βββ dispatcher.go # Single-threaded job processor
β β βββ bindings.go # JavaScript API bindings
β β βββ handlers.go # Express.js compatible routing
β βββ api/
β β βββ execute.go # /v1/execute endpoint for code execution
β βββ web/
β β βββ router.go # Dynamic route handling
β βββ mcp/
β βββ server.go # MCP server integration
βββ pkg/
β βββ doc/ # Documentation package
β βββ docs/ # Embedded documentation files
β βββ doc.go # Documentation access functions
βββ test-scripts/ # Example JavaScript applications
βββ scripts/ # Runtime JavaScript storage
π¦ Getting Started
1. Start the Server
cd cmd/experiments/js-web-server
go run . serve
2. Create Your First Endpoint
# Create a simple greeting endpoint (Express.js style)
go run . execute "
app.get('/greet', (req, res) => {
const name = req.query.name || 'World';
res.json({
message: 'Hello, ' + name + '!',
timestamp: new Date().toISOString()
});
});
console.log('Greeting endpoint created!');
"
3. Test Your Endpoint
Visit http://localhost:8080/greet?name=Alice or use curl:
curl "http://localhost:8080/greet?name=Alice"
# {"message":"Hello, Alice!","timestamp":"2024-01-15T10:30:00.000Z"}
4. Create a Database-Driven API
go run . execute "
// Create users table
db.query(\`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
)\`);
// Add sample data
db.query('INSERT OR IGNORE INTO users (name, email) VALUES (?, ?)', ['Alice', 'alice@example.com']);
db.query('INSERT OR IGNORE INTO users (name, email) VALUES (?, ?)', ['Bob', 'bob@example.com']);
// Create API endpoint (Express.js style)
app.get('/api/users', (req, res) => {
const users = db.query('SELECT * FROM users');
res.json({ users, total: users.length });
});
console.log('Users API created!');
"
Test it: curl http://localhost:8080/api/users
5. Build a Complete Web Page
go run . execute "
app.get('/users', (req, res) => {
const users = db.query('SELECT * FROM users');
const html = \`<!DOCTYPE html>
<html>
<head>
<title>User Directory</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.user { background: #f5f5f5; margin: 10px 0; padding: 15px; border-radius: 5px; }
</style>
</head>
<body>
<h1>User Directory</h1>
\${users.map(user => \`
<div class=\"user\">
<strong>\${user.name}</strong><br>
<a href=\"mailto:\${user.email}\">\${user.email}</a>
</div>
\`).join('')}
</body>
</html>\`;
res.send(html);
});
console.log('User directory page created!');
"
Visit http://localhost:8080/users to see your web page!
π Express.js API
Core Routing Methods
// HTTP method routing
app.get('/path', (req, res) => { /* GET handler */ });
app.post('/path', (req, res) => { /* POST handler */ });
app.put('/path', (req, res) => { /* PUT handler */ });
app.delete('/path', (req, res) => { /* DELETE handler */ });
app.patch('/path', (req, res) => { /* PATCH handler */ });
// Route parameters
app.get('/users/:id/posts/:postId', (req, res) => {
const { id, postId } = req.params;
res.json({ userId: id, postId });
});
Request Object (req)
app.get('/info', (req, res) => {
res.json({
method: req.method, // HTTP method
path: req.path, // URL path
query: req.query, // Query parameters
params: req.params, // Route parameters
headers: req.headers, // HTTP headers
body: req.body, // Request body (auto-parsed JSON)
cookies: req.cookies, // Cookies
ip: req.ip // Client IP
});
});
Response Object (res)
app.get('/response-examples', (req, res) => {
// JSON response
res.json({ message: 'Hello' });
// Status codes
res.status(404).json({ error: 'Not found' });
// HTML response
res.send('<h1>Hello World</h1>');
// Redirects
res.redirect('/new-location');
// Headers
res.set('X-Custom-Header', 'value');
// Cookies
res.cookie('sessionId', 'abc123', { maxAge: 3600000 });
});
Database Integration
// Create tables
db.query(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)`);
// Insert data
app.post('/users', (req, res) => {
const { name, email } = req.body;
db.query('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
res.status(201).json({ message: 'User created' });
});
// Query data
app.get('/users', (req, res) => {
const users = db.query('SELECT * FROM users ORDER BY created_at DESC');
res.json({ users, count: users.length });
});
Global State
// Initialize application state
if (!globalState.app) {
globalState.app = {
version: '1.0.0',
startTime: new Date(),
requestCount: 0
};
}
// Use persistent state
app.get('/stats', (req, res) => {
globalState.app.requestCount++;
res.json({
version: globalState.app.version,
uptime: new Date() - globalState.app.startTime,
requests: globalState.app.requestCount
});
});
π§ Advanced Features
Load Scripts on Startup
Create JavaScript files in a directory and load them when the server starts:
# Create script directory
mkdir my-api
echo "registerHandler('GET', '/status', () => ({status: 'running'}));" > my-api/status.js
# Start server with scripts
go run . serve --scripts my-api/
Persistent State Management
// Initialize application state
if (!globalState.app) {
globalState.app = {
version: "1.0.0",
startTime: new Date(),
requestCount: 0
};
}
// Track requests (Express.js style)
app.get("/stats", (req, res) => {
res.json({
version: globalState.app.version,
uptime: Math.floor((new Date() - globalState.app.startTime) / 1000),
requests: ++globalState.app.requestCount
});
});
File Serving
// Serve CSS files
registerFile("/styles.css", () => `
body { background: #f0f0f0; font-family: Arial; }
.container { max-width: 800px; margin: 0 auto; }
`);
// Serve dynamic content
registerFile("/data.json", () => {
const data = db.query("SELECT * FROM metrics");
return JSON.stringify(data);
});
π Monitoring and Debugging
Built-in Endpoints
The server includes several built-in endpoints:
GET /health- Health checkGET /- Welcome messagePOST /counter- Request counter
Logging
Configure logging levels for development and production:
# Development - see everything
go run . serve --log-level debug
# Production - errors and warnings only
go run . serve --log-level warn
JavaScript Console
Use console methods in your JavaScript code:
console.log("Info message");
console.warn("Warning message");
console.error("Error message");
console.debug("Debug information");
π Deployment
Docker
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o js-playground ./cmd/experiments/js-web-server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/js-playground .
EXPOSE 8080
CMD ["./js-playground", "serve"]
Environment Variables
export PORT=8080
export DB_PATH=/data/production.sqlite
export LOG_LEVEL=info
π Performance
- Throughput: 100-1000 RPS depending on JavaScript complexity
- Latency: Sub-millisecond for simple handlers
- Memory: Efficient single JavaScript context
- Concurrency: Single-threaded JavaScript execution with Go-based HTTP handling
π€ Contributing
This is an experimental project demonstrating the integration of JavaScript runtime with Go web servers. Feel free to explore, modify, and extend the functionality!
π License
This project is part of the go-go-mcp experimental suite.
Documentation
ΒΆ
There is no documentation for this package.
Directories
ΒΆ
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
repo-test
command
|
|
|
internal
|
|
|
web/templates
templ: version: v0.3.894
|
templ: version: v0.3.894 |
|
pkg
|
|