Lightweight REST API for OpenWorkers platform using Hono framework and Bun runtime.
- Hono - Ultra-fast web framework
- Postgate - HTTP-based PostgreSQL access via postgate
- Zod validation - Type-safe input/output validation
- Pure REST - No GraphQL complexity
- JWT auth - Using
hono/jwt - Standalone binary - Compile to single executable
src/
├── services/
│ ├── db/
│ │ ├── sql-client.ts - Postgate SQL client (named params support)
│ │ ├── users.ts - User DB queries
│ │ ├── workers.ts - Worker DB queries
│ │ ├── crons.ts - Cron DB queries
│ │ ├── databases.ts - Database DB queries
│ │ ├── environments.ts - Environment DB queries
│ │ └── domains.ts - Domain DB queries
│ ├── postgate.ts - Postgate HTTP client
│ ├── auth.ts - Authentication logic
│ ├── workers.ts - Workers business logic
│ ├── crons.ts - Crons business logic
│ ├── databases.ts - Databases business logic
│ ├── environments.ts - Environments business logic
│ └── domains.ts - Domains business logic
├── routes/
│ ├── auth.ts - Auth endpoints
│ ├── users.ts - User endpoints
│ ├── workers.ts - Workers endpoints
│ ├── crons.ts - Crons endpoints
│ ├── databases.ts - Databases endpoints
│ ├── environments.ts - Environments endpoints
│ └── domains.ts - Domains endpoints
├── middlewares/
│ └── auth.ts - JWT middleware
├── types/
│ ├── schemas/ - Zod validation schemas
│ ├── validators.ts - Schema validators
│ └── index.ts - Type exports
├── utils/
│ └── validate.ts - Response validation helpers
├── config/
│ └── index.ts - Configuration
└── index.ts - Main app
# Install dependencies
bun install
# Create .env from example
cp .env.example .env
# Edit .env with your Postgate URL/tokens and JWT secrets
# Run development server (hot reload)
bun run dev
# Production (run with Bun)
bun run start
# Compile standalone binary
bun run compile
# → Creates dist/openworkers-api (executable)POST /api/v1/openid/github- Initiate GitHub OAuth flowGET /api/v1/callback/github- GitHub OAuth callback (creates JWT)POST /api/v1/refresh- Refresh access token using refresh token
GET /api/v1/profile- Get current user profile
GET /api/v1/workers- List all workersGET /api/v1/workers/name-exists/:name- Check if worker name existsGET /api/v1/workers/:id- Get single workerPOST /api/v1/workers- Create workerPUT /api/v1/workers/:id- Update workerPOST /api/v1/workers/:id/crons- Create cron for workerDELETE /api/v1/workers/:id- Delete worker
POST /api/v1/crons- Create cronPUT /api/v1/crons/:id- Update cronDELETE /api/v1/crons/:id- Delete cron
GET /api/v1/environments- List all environmentsGET /api/v1/environments/:id- Get environment by ID (includes values)POST /api/v1/environments- Create environmentPUT /api/v1/environments/:id- Update environment (name/desc and/or values)DELETE /api/v1/environments/:id- Delete environment
GET /api/v1/domains- List all domainsPOST /api/v1/domains- Create domainDELETE /api/v1/domains/:name- Delete domain
All /api/v1/* endpoints (except auth endpoints) require JWT Bearer token in Authorization header:
Authorization: Bearer <token>
OAuth flow:
- User initiates login →
POST /api/v1/openid/github - GitHub redirects to →
GET /api/v1/callback/github?code=... - Server exchanges code for user profile
- Creates/finds user in DB
- Issues JWT tokens (access + refresh)
- Returns tokens in response body + sets cookie
All database access goes through Postgate - a secure HTTP proxy for PostgreSQL.
import { sql } from './services/db/sql-client';
// Named parameters ($name style)
const users = await sql<User>('SELECT * FROM users WHERE id = $id', { id: 1 });
// Positional parameters ($1 style)
const users = await sql<User>('SELECT * FROM users WHERE id = $1', [1]);
// Result is an array with .count property
console.log(users[0], users.count);Why Postgate?
- No native Postgres driver needed - just HTTP
fetch() - Multi-tenant isolation via schema separation
- SQL validation and injection prevention
- Token-based access control per database
- Same API works from workers (edge runtime)
- Auth routes (GitHub OAuth, refresh)
- Users routes (profile)
- Workers routes (CRUD + name uniqueness check)
- Databases routes (CRUD + token management via Postgate)
- Environments routes (CRUD + values management)
- Domains routes (CRUD)
- Crons routes (CRUD)
- Zod input/output validation
- JWT authentication middleware
- Standalone binary compilation
- Postgate integration (HTTP-based Postgres access)
- Error handling middleware (standardized error responses)
- Rate limiting
- Tests (unit + integration)
- API documentation (OpenAPI/Swagger)