@ailnaf/uai
v0.1.0
Published
Minimal Bun-native HTTP framework. Express-style routing, WebSocket, GraphQL.
Readme
uai
Minimal Bun-native HTTP framework. Express-style routing, WebSocket, and GraphQL — zero abstractions, no polyfills.
import { Router, cors, logger } from 'fuai'
const app = new Router()
.use(cors({ origin: '*' }))
.use(logger())
.get('/users/:id', (req, ctx) => Response.json({ id: ctx.params.id! }))
.post('/users', authMiddleware, async (req, ctx) => {
const body = await req.json()
return Response.json(body, { status: 201 })
})
.ws('/chat', { open(ws) { ws.send('connected!') } })
.graphql('/graphql', { schema, resolvers })
Bun.serve({ fetch: app.fetch(), websocket: app.websocket() })Features
- Express-style —
.get(path, ...middlewares, handler),.use(mw),.use('/path', router) - WebSocket — built-in, no
wspackage needed - GraphQL — built-in via
.graphql()with optional GraphiQL - Type-safe —
defineMiddleware<T>()for ctx extension - Fast — trie-based routing, ~57k req/s on a simple route
- Zero deps — only
graphqland@graphql-tools/schema(optional, only for.graphql())
Quick Start
import { Router } from 'uai'
const router = new Router()
.get('/', () => Response.json({ hello: 'world' }))
const server = Bun.serve({ fetch: router.fetch() })API
Route Methods
.get(path, ...middlewares, handler)
.post(path, ...middlewares, handler)
.put(path, ...middlewares, handler)
.delete(path, ...middlewares, handler)
.patch(path, ...middlewares, handler)
.head(path, ...middlewares, handler)
.options(path, ...middlewares, handler)
.all(path, ...middlewares, handler) // matches any method
.route(method, path, ...middlewares, handler)Middleware
// Global
.use((req, ctx, next) => {
console.log(`${req.method} ${new URL(req.url).pathname}`)
return next(req, ctx)
})
// Path-scoped
.use('/api', authMiddleware)
// Sub-router
.use('/api', apiRouter)
// Per-route
.get('/admin', authMiddleware, adminHandler)Error Handling
.onError((err, req, ctx) =>
Response.json({ error: err.message }, { status: 500 }),
)
.onWsError((err, ws, ctx) => console.error('WS error:', err))Type-safe Context
import { defineMiddleware, defineRoute } from 'uai'
const auth = defineMiddleware<{ user: { name: string } }>((req, ctx, next) => {
ctx.user = { name: req.headers.get('Authorization') ?? 'guest' }
return next(req, ctx)
})
const handler = defineRoute<{ user: { name: string } }>((req, ctx) =>
Response.json({ name: ctx.user.name }),
)
router.get('/profile', auth, handler)Or augment the global context:
declare module 'uai' {
interface Context {
user?: { name: string }
}
}WebSocket
.ws('/ws', {
open(ws, ctx) { ws.send('connected') },
message(ws, ctx, data) { ws.send(`echo: ${data}`) },
close(ws, ctx) { console.log('disconnected') },
})GraphQL
.graphql('/graphql', {
schema: `type Query { hello: String }`,
resolvers: { Query: { hello: () => 'world' } },
graphiql: true, // enables GraphiQL UI at GET /graphql
})Benchmarks
GET /hello, 100 concurrent connections:
| Framework | Req/s | |-----------|-------| | UAI | 57,572 | | Hono | 14,128 | | Express | 13,162 | | Fastify | 13,735 |
License
MIT
