Overview
Start an Elysia server with documentation and error handling.
Features
- Swagger documentation
- Graceful shutdown
- Error handling
- Health check
Installation
npx hanma add elysia-basic --framework elysia
Dependencies
elysia, @elysiajs/swagger
Code
import { Elysia, t } from "elysia";
import { swagger } from "@elysiajs/swagger";
const isProd = process.env.NODE_ENV === "production";
const getErrorMessage = (error: unknown): string => {
if (error instanceof Error) return error.message;
if (typeof error === "string") return error;
if (
typeof error === "object" &&
error !== null &&
"message" in error &&
typeof (error as { message?: unknown }).message === "string"
) {
return (error as { message: string }).message;
}
return "Unknown error";
};
// Store app instance for shutdown
// Using flexible type since Elysia's decorator chain creates complex types
let appInstance: { stop: () => Promise<void> } | null = null;
export const startServer = () => {
// Create base app with error handling
let app = new Elysia({ name: "production-api" })
/* ----------------------------- */
/* Error definitions */
/* ----------------------------- */
.error({
BadRequest: class BadRequest extends Error {},
Unauthorized: class Unauthorized extends Error {},
Forbidden: class Forbidden extends Error {},
NotFound: class NotFound extends Error {},
})
/* ----------------------------- */
/* Global error handler */
/* ----------------------------- */
.onError(({ code, error, set }) => {
const statusMap: Record<string, number> = {
BadRequest: 400,
Unauthorized: 401,
Forbidden: 403,
NotFound: 404,
VALIDATION: 400,
INTERNAL_SERVER_ERROR: 500,
};
set.status = statusMap[code] ?? 500;
const message = getErrorMessage(error);
if (!isProd || set.status >= 500) {
console.error(`[${code}]`, error);
}
return {
success: false,
code,
message:
isProd && set.status === 500 ? "Internal Server Error" : message,
timestamp: new Date().toISOString(),
};
});
// Add swagger in dev mode
if (!isProd) {
app = app.use(
swagger({
documentation: {
info: {
title: process.env.npm_package_name || "API",
version: process.env.npm_package_version || "1.0.0",
},
},
})
);
}
// Add routes
app
.get(
"/health",
() => ({
status: "ok",
uptime: Math.floor(Bun.nanoseconds() / 1e9),
timestamp: new Date().toISOString(),
}),
{
response: t.Object({
status: t.String(),
uptime: t.Number(),
timestamp: t.String(),
}),
}
)
.get("/", () => ({ message: "Elysia API is running" }), {
response: t.Object({
message: t.String(),
}),
});
// Store instance and start listening
appInstance = app;
const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => {
console.log(`Elysia running on http://localhost:${PORT}`);
if (!isProd) {
console.log(`Swagger docs: http://localhost:${PORT}/swagger`);
}
});
return app;
};
let isShuttingDown = false;
export const shutdown = async (signal: string) => {
// Prevent multiple shutdown attempts
if (isShuttingDown || !appInstance) return;
isShuttingDown = true;
console.log(`${signal} received. Shutting down...`);
try {
await appInstance.stop();
} catch (err) {
// Ignore errors if already stopped
}
appInstance = null;
process.exit(0);
};
Usage
// Server starts automatically
bun run src/index.ts
Dependencies
elysia@elysiajs/swagger
Frequently Asked Questions
How do I install Elysia Basic Server?
Run the following command:
npx hanma add elysia-basic --framework elysiaWhat dependencies are required?
This snippet requires: elysia, @elysiajs/swagger. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/index.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.