To help improve the stability of a hosted servers a health check route can be used to ensure services are working as expected. Here is an example of an Express.js application in TypeScript that includes a route for a health check that verifies the DB connection to PostgreSQL:
First, install the necessary dependencies:
npm install express pg
npm install --save-dev @types/express @types/pg
Next, create a new file app.ts
and paste the following code:
import express from 'express';
import { Pool } from 'pg';
const app = express();
// Create a new pool with the PostgreSQL database connection details
const pool = new Pool({
user: 'db_user',
host: 'localhost',
database: 'mydb',
password: 'mysecretpassword',
port: 5432,
});
// Define a route for the health check
app.get('/healthCheck', async (req, res) => {
try {
// Use the connection pool to acquire a connection
const client = await pool.connect();
// Release the connection back to the pool
client.release();
// Send a 200 OK status response
res.sendStatus(200);
} catch (err) {
// Send a 500 Internal Server Error status response if there was an error
res.sendStatus(500);
}
});
// Start the Express.js server
app.listen(3000, () => {
console.log('Server running on port 3000');
});
In the above code, we first import the necessary dependencies (express
and pg
). We then create a new instance of the Express.js
app using express()
. We also create a new connection pool to the PostgreSQL database using the Pool
class from the pg
package.
We then define a route for the health check at the /healthCheck
endpoint using app.get()
. Inside the route handler function, we use the connection pool to acquire a connection to the database using pool.connect()
. If the connection is successful, we release the connection back to the pool
and send a 200 OK status response using res.sendStatus(200)
. If there was an error, we catch the error and send a 500 Internal Server Error status response using res.sendStatus(500)
.
We start the Express.js
server by calling app.listen()
and passing in the port number we want to listen on (in this case, port 3000).
Testing using SuperTest
Example of how you could write integration tests to verify that the code works:
First, install the necessary dependencies:
npm install --save-dev jest supertest ts-jest @types/jest @types/supertest
Next, create a new file app.test.ts
in the same directory as app.ts
and paste the following code:
import request from 'supertest';
import app from './app';
describe('healthCheck route', () => {
it('should return 200 OK if the database connection is successful', async () => {
// Make a GET request to the /healthCheck endpoint
const res = await request(app).get('/healthCheck');
// Expect a 200 OK status response
expect(res.status).toBe(200);
});
});
In the above code, we first import the necessary dependencies (supertest
and app
from ./app
). We then define a describe
block for the healthCheck
route and an it
block for the happy path scenario where the database connection is successful.
Inside the it
block, we use request(app)
to make a GET
request to the /healthCheck
endpoint. We then use expect(res.status).toBe(200)
to assert that the response status is 200 OK.
Now, we need to update our package.json
file to run the integration tests. Add the following to the "scripts"
section:
"test": "jest"
Finally, run the integration tests by executing the following command:
npm test
This should run the integration tests and output something like the following:
PASS ./app.test.ts
healthCheck route
✓ should return 200 OK if the database connection is successful (34 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
This indicates that the integration tests passed and the /healthCheck route is functioning correctly.
If you want to test the error case where the database connection fails, you can add another it
block to the describe block in app.test.ts
. Here's an example of how you could write the test:
it('should return 500 Internal Server Error if the database connection fails', async () => {
// Force the pool to return an error when connecting to the database
jest.spyOn(app.locals.pool, 'connect').mockImplementation(() => {
throw new Error('Connection failed');
});
// Make a GET request to the /healthCheck endpoint
const res = await request(app).get('/healthCheck');
// Expect a 500 Internal Server Error status response
expect(res.status).toBe(500);
});
In the above code, we use Jest's spyOn
function to mock the pool.connect()
method and force it to throw an error when connecting to the database. We then make a GET request to the /healthCheck
endpoint and use expect(res.status).toBe(500)
to assert that the response status is 500 Internal Server Error.
When you run the integration tests again, you should see that both tests pass:
PASS ./app.test.ts
healthCheck route
✓ should return 200 OK if the database connection is successful (32 ms)
✓ should return 500 Internal Server Error if the database connection fails (12 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Great! That means our integration tests are passing for both the happy and error path scenarios. Now, we can be confident that our /healthCheck route is functioning correctly and verifying the database connection before responding with the appropriate status code.
Top comments (0)