Skip to content

Structuring an application

Tetsu reads the routes it is given, not files or folders, so any layout works. Here is a simple one to start from:

src/
main.ts starts the server
app.ts builds the application
notes/
controller.ts the routes
service.ts the logic and the queries
schemas.ts what comes in and what goes out
controller.test.ts

Two habits are worth keeping whatever the layout.

app.ts makes the services and returns the application:

src/app.ts
import type { Database } from "bun:sqlite";
import { createApp } from "@tetsujs/core";
import { notesController } from "./notes/controller";
import { NoteService } from "./notes/service";
export function buildApp(
db: Database
db
: Database) {
const
const notes: NoteService
notes
= new NoteService(
db: Database
db
);
return createApp({ routes: notesController(
const notes: NoteService
notes
) });
}

main.ts serves it, and a test builds the same application on a database in memory, so the test runs what the server runs:

src/main.ts
import { Database } from "bun:sqlite";
import { buildApp } from "./app";
Bun.serve({ ...buildApp(new Database("notes.sqlite")),
port?: string | number | undefined

The port the server listens on

@default ― process.env.PORT || "3000"

port
: 3000 });
src/notes/controller.test.ts
import { Database } from "bun:sqlite";
import { serve } from "@tetsujs/core/testing";
import { expect, test } from "bun:test";
import { buildApp } from "../app";
const
const request: RequestFn
request
= serve(buildApp(new Database(":memory:")));
test("lists notes", async () => {
expect((await
const request: RequestFn
(path: string, init?: RequestInit) => Promise<Response>
request
("/notes")).
status: number

The status read-only property of the Response interface contains the HTTP status codes of the response.

MDN Reference

status
).toBe(200);
});

A service takes values, returns values and throws its own errors; routes and hooks deal with requests. Then a service is tested without a server, and a scheduled job or a script can use it too.

A small runnable application laid out much this way is examples/app.