Skip to content

Commit afa9413

Browse files
authored
Merge pull request #29 from NodeFactoryIo/mpetrunic/env
Use fastify-env for env validation and casting
2 parents 31e188b + 4fa47cb commit afa9413

File tree

7 files changed

+59
-26
lines changed

7 files changed

+59
-26
lines changed

Diff for: docker-compose.e2e.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services:
55
build:
66
context: .
77
target: dev
8-
command: sh -c "yarn run test:e2e"
8+
command: sh -c "sleep 5 && yarn run test:e2e"
99
image: nodefactory/nodejs-ts-starter:${IMAGE_TAG:-latest}
1010
container_name: "${BACKEND_CONTAINER_NAME:-nodejs-backend}"
1111
depends_on:

Diff for: src/App.ts

+24-11
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,28 @@ export class App {
2020

2121
public readonly instance: FastifyInstance;
2222

23-
constructor() {
24-
this.instance = fastify({
23+
protected constructor(instance: FastifyInstance) {
24+
this.instance = instance;
25+
}
26+
27+
/**
28+
* Initializes fastify, env variables and register routes.
29+
* Rest of plugins, db and port bind are initialized on start method.
30+
*/
31+
public static async init(): Promise<App> {
32+
const instance = fastify({
2533
logger: fastifyLogger,
2634
return503OnClosing: true
2735
});
28-
this.registerPlugins();
36+
const app = new App(instance);
37+
await app.registerPlugins();
38+
return app;
2939
}
3040

3141
public async start(): Promise<void> {
3242
try {
33-
await this.initDb();
3443

44+
await this.initDb();
3545
await this.instance.ready();
3646
logger.info(this.instance.printRoutes());
3747
return new Promise((resolve, reject) => {
@@ -72,13 +82,14 @@ export class App {
7282
await this.instance.db.runMigrations({transaction: "all"});
7383
}
7484

75-
private registerPlugins(): void {
85+
private async registerPlugins(): Promise<void> {
7686
this.instance.register(fastifyEnv, envPluginConfig);
87+
await this.instance.after();
7788
this.instance.register(fastifyCompress, {global: true, encodings: ["gzip", "deflate"]});
78-
this.instance.register(fastifyCors, {origin: process.env.CORS_ORIGIN || true});
89+
this.instance.register(fastifyCors, {origin: this.instance.config.CORS_ORIGIN});
7990
this.instance.register(fastifyFormBody);
8091
this.instance.register(fastifyHelmet);
81-
this.instance.register(fastifyRateLimit, {max: parseInt(process.env.MAX_REQ_PER_MIN || "100"), timeWindow: '1 minute'});
92+
this.instance.register(fastifyRateLimit, {max: this.instance.config.MAX_REQ_PER_MIN, timeWindow: '1 minute'});
8293
this.instance.register(fastifySensible);
8394
this.instance.register(fastifySwagger, SWAGGER_CONFIG);
8495
this.instance.register(fastifyHealthCheck, {
@@ -91,10 +102,12 @@ export class App {
91102
}
92103
}
93104
});
94-
this.instance.register(fastifyMetrics, {
95-
blacklist: '/metrics',
96-
enableDefaultMetrics: true
97-
});
105+
if(this.instance.config.NODE_ENV !== "test") {
106+
this.instance.register(fastifyMetrics, {
107+
blacklist: '/metrics',
108+
enableDefaultMetrics: true
109+
});
110+
}
98111
this.instance.register(routesPlugin);
99112
}
100113
}

Diff for: src/config/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export const config: fasitfyEnvOpt = {
55
schema: {
66
type: "object",
77
properties: {
8+
NODE_ENV: {
9+
type: 'string',
10+
default: 'prod'
11+
},
812
SERVER_ADDRESS: {
913
type: 'string',
1014
default: '0.0.0.0'
@@ -13,6 +17,14 @@ export const config: fasitfyEnvOpt = {
1317
type: 'number',
1418
default: 3000
1519
},
20+
CORS_ORIGIN: {
21+
type: 'string',
22+
default: "*"
23+
},
24+
MAX_REQ_PER_MIN: {
25+
type: 'number',
26+
default: 100
27+
},
1628
}
1729
},
1830
env: true
@@ -21,8 +33,11 @@ export const config: fasitfyEnvOpt = {
2133
declare module 'fastify' {
2234
interface FastifyInstance {
2335
config: {
36+
NODE_ENV: string | "test" | "prod";
2437
SERVER_ADDRESS: string;
2538
SERVER_PORT: number;
39+
CORS_ORIGIN: string;
40+
MAX_REQ_PER_MIN: number;
2641
};
2742
}
2843
}

Diff for: src/index.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {App} from "./App";
22
import nodeCleanup from "node-cleanup";
33

4-
const app = new App();
4+
App.init().then((app) => {
5+
nodeCleanup(function (exitCode, signal) {
6+
app.stop(signal as string);
7+
nodeCleanup.uninstall();
8+
return false;
9+
});
10+
11+
app.start();
12+
})
513

6-
nodeCleanup(function (exitCode, signal) {
7-
app.stop(signal as string);
8-
nodeCleanup.uninstall();
9-
return false;
10-
});
1114

12-
app.start();

Diff for: test/e2e/app-setup.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import {App} from "../../src/App";
2-
export const app = new App();
2+
3+
let instance: App;
4+
5+
export const app = (): App => instance;
36

47
before(async () => {
5-
await app.start();
8+
instance = await App.init();
9+
await instance.start();
610
});
711

812
after(async () => {
9-
await app.stop("TEST");
13+
await instance.stop("TEST");
1014
});

Diff for: test/e2e/sample.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe("Sample e2e test", function () {
1313
});
1414

1515
it("Should successfully query database", async function () {
16-
const res = await app.instance.inject({
16+
const res = await app().instance.inject({
1717
method: "GET",
1818
path: "/samples",
1919
});

Diff for: test/unit/controllers/sample.spec.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ describe("sample controller", function () {
1313
let app: App;
1414
let sampleRepositoryStub: SinonStubbedInstance<SampleRepository>;
1515

16-
beforeEach(function () {
16+
beforeEach(async function () {
1717
logger.silent = true;
18-
app = new App();
18+
app = await App.init();
1919
sampleRepositoryStub = sinon.createStubInstance(SampleRepository);
2020
app.instance.decorate("db", {
2121
getCustomRepository: () => sampleRepositoryStub
@@ -24,7 +24,6 @@ describe("sample controller", function () {
2424

2525
afterEach(async function () {
2626
logger.silent = false;
27-
app.instance.metrics.client.register.clear();
2827
});
2928

3029
it("get samples", async function () {

0 commit comments

Comments
 (0)