Initial web app consumption/integration #5

Merged
joe merged 6 commits from web-app-integration into master 2026-02-23 21:15:19 +00:00
7 changed files with 80 additions and 16 deletions
Showing only changes of commit b7acc9e352 - Show all commits

View file

@ -14,7 +14,7 @@ Start the API:
```bash
npm run start:dev
```
Verify running via the [healthcheck](http://localhost:3000/common-cents/healthcheck) endpoint.
To verify the API is running access the interactive [documentation](http://localhost:3000/common-cents/docs).
Default port (`3000`) can be changed by setting the `PORT=` environment variable.

68
package-lock.json generated
View file

@ -14,12 +14,13 @@
"@nestjs/core": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.6",
"@nestjs/typeorm": "^11.0.0",
"pg": "^8.18.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.28"
"sqlite3": "^5.0.2",
"typeorm": "^0.3.6"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
@ -2071,6 +2072,12 @@
"node": ">=8"
}
},
"node_modules/@microsoft/tsdoc": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz",
"integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==",
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
@ -2526,6 +2533,39 @@
"tslib": "^2.1.0"
}
},
"node_modules/@nestjs/swagger": {
"version": "11.2.6",
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.6.tgz",
"integrity": "sha512-oiXOxMQqDFyv1AKAqFzSo6JPvMEs4uA36Eyz/s2aloZLxUjcLfUMELSLSNQunr61xCPTpwEOShfmO7NIufKXdA==",
"license": "MIT",
"dependencies": {
"@microsoft/tsdoc": "0.16.0",
"@nestjs/mapped-types": "2.1.0",
"js-yaml": "4.1.1",
"lodash": "4.17.23",
"path-to-regexp": "8.3.0",
"swagger-ui-dist": "5.31.0"
},
"peerDependencies": {
"@fastify/static": "^8.0.0 || ^9.0.0",
"@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1",
"class-transformer": "*",
"class-validator": "*",
"reflect-metadata": "^0.1.12 || ^0.2.0"
},
"peerDependenciesMeta": {
"@fastify/static": {
"optional": true
},
"class-transformer": {
"optional": true
},
"class-validator": {
"optional": true
}
}
},
"node_modules/@nestjs/testing": {
"version": "11.1.13",
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.13.tgz",
@ -2668,6 +2708,13 @@
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@scarf/scarf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
"hasInstallScript": true,
"license": "Apache-2.0"
},
"node_modules/@sinclair/typebox": {
"version": "0.34.48",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz",
@ -4071,7 +4118,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/array-timsort": {
@ -7777,7 +7823,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@ -9475,9 +9520,9 @@
"license": "MIT"
},
"node_modules/qs": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@ -10433,6 +10478,15 @@
"node": ">=8"
}
},
"node_modules/swagger-ui-dist": {
"version": "5.31.0",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.31.0.tgz",
"integrity": "sha512-zSUTIck02fSga6rc0RZP3b7J7wgHXwLea8ZjgLA3Vgnb8QeOl3Wou2/j5QkzSGeoz6HusP/coYuJl33aQxQZpg==",
"license": "Apache-2.0",
"dependencies": {
"@scarf/scarf": "=1.4.0"
}
},
"node_modules/symbol-observable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",

View file

@ -25,12 +25,13 @@
"@nestjs/core": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.6",
"@nestjs/typeorm": "^11.0.0",
"pg": "^8.18.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.28"
"sqlite3": "^5.0.2",
"typeorm": "^0.3.6"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View file

@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { HealthcheckController } from './healthcheck.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MerchantsModule } from './merchants/merchants.module';
import { TagsModule } from './tags/tags.module';
@ -40,6 +40,6 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
SubCategoriesModule,
ExpensesModule
],
controllers: [AppController]
controllers: [HealthcheckController]
})
export class AppModule { }

View file

@ -1,7 +1,7 @@
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AppController {
export class HealthcheckController {
@Get('healthcheck')
health() {
return { status: 'healthy' };

View file

@ -1,11 +1,20 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
async function bootstrap(): Promise<void> {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.enableCors();
app.setGlobalPrefix(process.env.PREFIX ?? 'common-cents');
const appPrefix = process.env.PREFIX ?? 'common-cents';
const config = new DocumentBuilder()
.setTitle('Common Cents API')
.setDescription('Documentation for Common Cents API')
.setVersion('1.0')
.build();
const documentFactory = () => SwaggerModule.createDocument(app, config);
SwaggerModule.setup(appPrefix + '/docs', app, documentFactory);
app.enableCors(); // TODO: Research if this is worth worrying about
app.setGlobalPrefix(appPrefix);
await app.listen(process.env.PORT ?? 3000);
}
void bootstrap();

View file

@ -4,7 +4,7 @@ import request from 'supertest';
import { App } from 'supertest/types';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
describe('HealthcheckController (e2e)', () => {
let app: INestApplication<App>;
beforeEach(async () => {