Skip to main content

Installation

Efesto ships two stacks from one package. Pick the tab for your runtime, the rest of the docs use the same groupId, so your choice follows you across pages.

Prerequisites

  • Node.js 12 or higher
  • npm, yarn, or pnpm
  • Familiarity with Express and TypeScript

Install

npm install efesto express
# or: yarn add efesto express / pnpm add efesto express
npm install -D typescript @types/node @types/express

Project structure

The only hard requirement is a routes directory whose files map to paths. A common layout:

my-efesto-api/
├── src/ (or lib/)
│ ├── routes/ # endpoints — file path becomes the URL path
│ │ └── users/
│ │ └── index.ts
│ ├── server.ts # or app.ts
│ └── ...
├── tsconfig.json
└── package.json

The Express stack additionally writes generated OpenAPI into a swagger-declarations/ folder (configurable). The Elysia stack serves OpenAPI from memory and writes nothing.

Your first endpoint

src/routes/users/index.ts — a service class. The file location (users/index.ts) becomes the path /users:

import { BaseApiService, SwaggerModel, SwaggerOptions } from "efesto";

class Users extends BaseApiService {
constructor() {
super(__filename);
}

swaggerModel: SwaggerModel = {
modelName: "User",
schemas: [
{
name: "User",
properties: {
id: "number",
name: "string",
email: "string::email",
},
},
],
};

_getSwagger: SwaggerOptions = {
operationId: "getUsers",
summary: "List users",
responses: { 200: "@User[]" }, // shorthand: an array of User
};

async _get(req, res) {
return res.json([{ id: 1, name: "Ada", email: "ada@example.com" }]);
}
}
export default Users;

src/app.ts — mount Efesto as Express middleware:

import express from "express";
import efesto from "efesto";
import path from "path";

const app = express();
app.use(express.json());

app.use(
"/api/v1",
efesto({
authMiddleware: (req, res, next) => next(), // your auth here
errorMiddleware: (req, res, next) => next(), // your error handling here
isProduction: process.env.NODE_ENV === "production",
options: {
absoluteDirRoutes: path.join(__dirname, "routes"),
relativeDirSwaggerDeclarationsPath: "swagger-declarations",
},
})
);

app.listen(3000, () => console.log("http://localhost:3000/api/v1"));

Run it:

npx ts-node src/app.ts   # dev
# or: tsc && node dist/app.js

GET http://localhost:3000/api/v1/users returns the list.

Viewing the documentation

Efesto writes OpenAPI .yaml files into swagger-declarations/. Bundle them and serve a UI with swagger-ui-express:

import swaggerUi from "swagger-ui-express";

// after the Efesto middleware (apis.json is the bundled document)
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(require("../swagger-declarations/apis.json")));

See Swagger Documentation for the full pipeline.

Troubleshooting

  • Routes not found — check absoluteDirRoutes (Express) / routesDir (Elysia) points at the real folder, and that isProduction matches your files: production scans .js, development scans .ts.
  • Express: nothing exported — a route file must export default a class extending BaseApiService.
  • Elysia: module skipped — a route file must export default a native Elysia instance or a class/instance extending BaseApiService; anything else is skipped with a warning.
  • Elysia: peer depselysia and @elysiajs/openapi are optional peers; if you use the Elysia stack you must install them yourself.

Next, learn the endpoint model or the full configuration.