@superfunctions/http
v0.1.2
Published
Framework-agnostic HTTP abstraction layer for Superfunctions libraries
Maintainers
Readme
@superfunctions/http
Framework-agnostic HTTP abstraction layer for building web APIs that work across Express, Hono, Fastify, Next.js, and more.
Installation
npm install @superfunctions/httpFor framework adapters:
# Express
npm install @superfunctions/http-express
# Hono
npm install @superfunctions/http-hono
# Fastify
npm install @superfunctions/http-fastify
# Next.js
npm install @superfunctions/http-next
# SvelteKit
npm install @superfunctions/http-sveltekitQuick Start
Define Your API (Framework Agnostic)
import { createRouter } from '@superfunctions/http';
const apiRouter = createRouter({
routes: [
{
method: 'GET',
path: '/users',
handler: async () => {
const users = await db.query('SELECT * FROM users');
return Response.json(users);
},
},
{
method: 'GET',
path: '/users/:id',
handler: async (req, ctx) => {
const user = await db.query(
'SELECT * FROM users WHERE id = ?',
[ctx.params.id]
);
return Response.json(user);
},
},
{
method: 'POST',
path: '/users',
handler: async (req, ctx) => {
const data = await ctx.json();
const user = await db.insert('users', data);
return Response.json(user, { status: 201 });
},
},
],
});Use with Express
import express from 'express';
import { toExpress } from '@superfunctions/http-express';
import { apiRouter } from './api';
const app = express();
app.use(express.json());
app.use('/api', toExpress(apiRouter));
app.listen(3000);Use with Hono
import { Hono } from 'hono';
import { toHono } from '@superfunctions/http-hono';
import { apiRouter } from './api';
const app = new Hono();
app.route('/api', toHono(apiRouter));
export default app;Use Directly (Universal Handler)
For Fetch-native frameworks:
import { createRouter } from '@superfunctions/http';
const router = createRouter({ routes: [...] });
// Cloudflare Workers
export default {
fetch: router.handle
};
// Deno
Deno.serve(router.handle);
// Bun
Bun.serve({ fetch: router.handle });Features
Middleware
const authMiddleware = async (req, ctx, next) => {
const token = req.headers.get('Authorization');
if (!token) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
ctx.user = await verifyToken(token);
return next();
};
const router = createRouter({
middleware: [authMiddleware],
routes: [...],
});Context
interface AppContext {
db: Database;
user?: User;
}
const router = createRouter<AppContext>({
context: async (req) => ({
db: adapter,
user: await getUser(req),
}),
routes: [
{
method: 'GET',
path: '/profile',
handler: async (req, ctx) => {
// ctx is typed as AppContext & RouteContext
return Response.json({ user: ctx.user });
},
},
],
});Error Handling
import { RouterError, UnauthorizedError } from '@superfunctions/http';
const router = createRouter({
routes: [
{
method: 'GET',
path: '/protected',
handler: async () => {
throw new UnauthorizedError('Invalid token');
},
},
],
onError: (error, req) => {
console.error('Error:', error);
return Response.json(
{ error: error.message },
{ status: error instanceof RouterError ? error.statusCode : 500 }
);
},
});Base Path
⚠️ Important: Only use basePath for standalone deployments without framework mounting.
// ✅ Good: Standalone deployment (Cloudflare Workers, Vercel Edge)
const router = createRouter({
basePath: '/api/v1',
routes: [
{ method: 'GET', path: '/users', handler: ... } // Accessible at /api/v1/users
]
});
export default { fetch: router.handle }; // or router.handler
// ❌ Bad: With framework mounting (creates double prefixing)
const router = createRouter({
basePath: '/v1', // Don't do this!
routes: [...]
});
app.use('/api', toExpress(router)); // Would need /api/v1/users
// ✅ Good: With framework mounting (no basePath)
const router = createRouter({
routes: [
{ method: 'GET', path: '/users', handler: ... }
]
});
app.use('/api/v1', toExpress(router)); // Accessible at /api/v1/usersRule of thumb:
- Standalone deployment → Use
basePathin router - Framework mounting → Use framework's mounting (e.g.,
app.use('/path', ...)) and omitbasePath
CORS
import { corsMiddleware } from '@superfunctions/http/middleware';
const router = createRouter({
middleware: [
corsMiddleware({
origin: 'https://example.com',
methods: ['GET', 'POST'],
credentials: true,
}),
],
routes: [...],
});API Reference
createRouter<TContext>(options)
Creates a framework-agnostic router.
Options:
routes: Array of route definitionsmiddleware?: Global middleware arraycontext?: Static context or factory functiononError?: Custom error handlerbasePath?: Base path prefix for all routescors?: CORS configuration
Returns: Router<TContext>
Route Definition
interface Route<TContext> {
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
path: string;
handler: RouteHandler<TContext>;
middleware?: Middleware<TContext>[];
meta?: Record<string, any>;
}Route Context
Every handler receives a context with:
interface RouteContext {
params: Record<string, string>; // Path parameters
query: URLSearchParams; // Query string
url: URL; // Full URL
json: () => Promise<any>; // Parse JSON body
formData: () => Promise<FormData>; // Parse form data
text: () => Promise<string>; // Get text body
}Framework Adapters
| Framework | Package | Function |
|-----------|---------|----------|
| Express | @superfunctions/http-express | toExpress(), toExpressHandler() |
| Hono | @superfunctions/http-hono | toHono() |
| Fastify | @superfunctions/http-fastify | toFastify() |
| Next.js | @superfunctions/http-next | toNextHandlers() |
| SvelteKit | @superfunctions/http-sveltekit | toSvelteKitHandler(), toSvelteKitHandlers() |
License
MIT
