feat(api): Hono backend skeleton with /health endpoint and test

This commit is contained in:
Bas van Rossem
2026-06-17 13:35:28 +02:00
parent f83c9a6384
commit 62c8597068
10 changed files with 1323 additions and 9 deletions

30
apps/api/package.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "@solelog/api",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "tsx src/index.ts",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"db:generate": "drizzle-kit generate",
"db:migrate": "tsx src/db/migrate.ts"
},
"dependencies": {
"@hono/node-server": "^1.13.7",
"@libsql/client": "^0.14.0",
"@solelog/shared": "workspace:*",
"better-auth": "^1.1.7",
"drizzle-orm": "^0.36.4",
"hono": "^4.6.14",
"zod": "^3.23.8"
},
"devDependencies": {
"drizzle-kit": "^0.30.1",
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"vitest": "^3.0.0"
}
}

8
apps/api/src/app.ts Normal file
View File

@@ -0,0 +1,8 @@
import { Hono } from 'hono';
import { health } from './routes/health';
export function createApp(): Hono {
const app = new Hono();
app.route('/', health);
return app;
}

6
apps/api/src/env.ts Normal file
View File

@@ -0,0 +1,6 @@
export const env = {
DATABASE_URL: process.env.DATABASE_URL ?? 'file:./data/app.db',
BETTER_AUTH_SECRET: process.env.BETTER_AUTH_SECRET ?? 'dev-insecure-secret-change-me',
BETTER_AUTH_URL: process.env.BETTER_AUTH_URL ?? 'http://localhost:3000',
PORT: Number(process.env.PORT ?? 3000),
};

8
apps/api/src/index.ts Normal file
View File

@@ -0,0 +1,8 @@
import { serve } from '@hono/node-server';
import { createApp } from './app';
import { env } from './env';
const app = createApp();
serve({ fetch: app.fetch, port: env.PORT }, (info) => {
console.log(`API listening on http://localhost:${info.port}`);
});

View File

@@ -0,0 +1,9 @@
import { Hono } from 'hono';
import { HealthResponse } from '@solelog/shared';
export const health = new Hono();
health.get('/health', (c) => {
const body: HealthResponse = { status: 'ok' };
return c.json(body);
});

View File

@@ -0,0 +1,11 @@
import { describe, it, expect } from 'vitest';
import { createApp } from '../src/app';
describe('GET /health', () => {
it('returns { status: "ok" }', async () => {
const app = createApp();
const res = await app.request('/health');
expect(res.status).toBe(200);
expect(await res.json()).toEqual({ status: 'ok' });
});
});

2
apps/api/test/setup.ts Normal file
View File

@@ -0,0 +1,2 @@
// Placeholder until Task 3 adds DB migration to the test setup.
export {};

15
apps/api/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
"types": ["node"],
"noEmit": true
},
"include": ["src", "test"]
}

View File

@@ -0,0 +1,9 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
setupFiles: ['./test/setup.ts'],
fileParallelism: false,
},
});