Create template

This commit is contained in:
Max
2025-04-21 21:05:52 +02:00
commit a22c8828b2
20 changed files with 4306 additions and 0 deletions

3022
server/api/data.json Normal file

File diff suppressed because it is too large Load Diff

38
server/main.ts Normal file
View File

@@ -0,0 +1,38 @@
import { Application } from "jsr:@oak/oak/application";
import { Router } from "jsr:@oak/oak/router";
import { oakCors } from "@tajpouria/cors";
import routeStaticFilesFrom from "./util/routeStaticFilesFrom.ts";
import data from "./api/data.json" with { type: "json" };
export const app = new Application();
const router = new Router();
router.get("/api/dinosaurs", (context) => {
context.response.body = data;
});
router.get("/api/dinosaurs/:dinosaur", (context) => {
if (!context?.params?.dinosaur) {
context.response.body = "No dinosaur name provided.";
}
const dinosaur = data.find((item) =>
item.name.toLowerCase() === context.params.dinosaur.toLowerCase()
);
context.response.body = dinosaur ?? "No dinosaur found.";
});
app.use(oakCors());
app.use(router.routes());
app.use(router.allowedMethods());
app.use(routeStaticFilesFrom([
`${Deno.cwd()}/client/dist`,
`${Deno.cwd()}/client/public`,
]));
if (import.meta.main) {
console.log("Server listening on port http://localhost:8000");
await app.listen({ port: 8000 });
}

68
server/main_test.ts Normal file
View File

@@ -0,0 +1,68 @@
import { assertEquals, assertExists } from "jsr:@std/assert";
import { afterAll, beforeAll, describe, it } from "jsr:@std/testing/bdd";
import { expect } from "jsr:@std/expect";
import { Application } from "jsr:@oak/oak/application";
import { Router } from "jsr:@oak/oak/router";
import { app } from "./main.ts";
import routeStaticFilesFrom from "./util/routeStaticFilesFrom.ts";
describe("Application", () => {
let serverInfo: { baseUrl: string; abortController: AbortController };
beforeAll(async () => {
console.log("Starting server");
serverInfo = await serve();
});
afterAll(() => {
console.log("Shutting down server");
serverInfo.abortController.abort();
});
it("can be created", () => {
assertExists(app);
assertEquals(app instanceof Application, true);
});
it("router accepts routes without throwing errors", () => {
const router = new Router();
app.use(router.routes());
assertExists(router);
});
it("can configure static routes", () => {
const staticFileMiddleware = routeStaticFilesFrom([
`${Deno.cwd()}/client/dist`,
`${Deno.cwd()}/client/public`,
]);
app.use(staticFileMiddleware);
assertExists(staticFileMiddleware);
});
it("can request home page from running server", async () => {
const response = await fetch(serverInfo.baseUrl);
const body = await response.text();
assertEquals(response.status, 200);
expect(body).toContain("<title>Vite + React + TS</title>");
});
});
async function serve(abortController = new AbortController()) {
let randomPort = 0;
app.listen({ port: randomPort, signal: abortController.signal });
await new Promise<void>((resolve) => {
app.addEventListener("listen", (ev) => {
randomPort = ev.port;
console.log(`Server running on http://localhost:${ev.port}`);
resolve();
});
});
return {
baseUrl: `http://localhost:${randomPort}`,
abortController: abortController,
};
}

View File

@@ -0,0 +1,19 @@
import { Next } from "jsr:@oak/oak/middleware";
import { Context } from "jsr:@oak/oak/context";
// Configure static site routes so that we can serve
// the Vite build output and the public folder
export default function routeStaticFilesFrom(staticPaths: string[]) {
return async (context: Context<Record<string, object>>, next: Next) => {
for (const path of staticPaths) {
try {
await context.send({ root: path, index: "index.html" });
return;
} catch {
continue;
}
}
await next();
};
}