Enhancing Error Tracking and Monitoring: Integrating Sentry in Node.js, Express.js, and MongoDB Backend Project

Saunak Surani
Widle Studio LLP
Published in
8 min readJul 27, 2023
Efficient Error Monitoring: Integrating Sentry in Node.js, Express.js, and MongoDB Backend Rest API Project

In modern web development, building robust applications requires a robust error-tracking and monitoring system. Sentry is a powerful tool that allows developers to identify, diagnose, and fix issues in real time. In this article, we will explore how to integrate Sentry into a Node.js, Express.js, and MongoDB backend REST API project for CRUD operations. By leveraging Sentry’s capabilities, we can gain valuable insights into our application’s health, track errors, and enhance the overall user experience.

Table of Contents

1. What is Sentry?
2. Setting Up the Node.js Backend
3. Integrating Sentry for Error Tracking

3.1. Installing the Sentry Package
3.2. Configuring Sentry in the Backend
4. Implementing CRUD Operations with MongoDB
4.1. Setting Up the MongoDB Connection
4.2. Creating the API Endpoints for CRUD Operations
5. Handling Errors and Capturing Events with Sentry
5.1. Capturing Errors in the Backend
5.2. Capturing Custom Events
6. Enhancing User Experience with Sentry
6.1. Monitoring Performance with Transaction Tracing
6.2. Managing Release and Environment Data
7. Integrating Sentry with Frontend Applications
8. Best Practices and Tips for Sentry Integration
9. Conclusion

1. What is Sentry?

Sentry is an open-source error tracking and monitoring platform that allows developers to identify, prioritize, and resolve issues in real time. It provides detailed error reports, stack traces, and insights into the root cause of errors, helping developers quickly diagnose and fix issues. Sentry supports multiple platforms and languages, including JavaScript, Node.js, Python, Java, and more. With Sentry’s powerful features, teams can ensure the stability and reliability of their applications.

2. Setting Up the Node.js Backend

To get started, let’s set up the Node.js backend for our project. Make sure you have Node.js and npm (Node Package Manager) installed on your system. Create a new directory for your project and initialize a new Node.js project using the following commands:

mkdir backend
cd backend
npm init -y

Next, let’s install the required dependencies for our backend:

npm install express mongoose body-parser

In this article, we will use Express.js as the web application framework and MongoDB as the database for our REST API project.

3. Integrating Sentry for Error Tracking

3.1. Installing the Sentry Package
To use Sentry in our Node.js backend, we need to install the `@sentry/node` package. This package provides the necessary tools to capture and report errors to the Sentry dashboard.

npm install @sentry/node

3.2. Configuring Sentry in the Backend
Before we can start capturing errors, we need to configure Sentry with our backend. Create a new file named `sentry.js` in the root of the backend directory and add the following code:

// sentry.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_SENTRY_DSN', // Replace with your Sentry DSN (Data Source Name)
});

You can obtain your Sentry DSN by signing in to your Sentry account and creating a new project for your backend application.

Next, import the `sentry.js` file in your main backend file (e.g., `app.js` or `index.js`) to ensure that Sentry is configured when the server starts:

// app.js
const express = require('express');
const sentry = require('./sentry');
const app = express();
// Other middleware and routes…
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});

With this setup, Sentry is now ready to capture errors in our backend.

4. Implementing CRUD Operations with MongoDB

Before we proceed with error tracking, let’s set up the MongoDB connection and create the API endpoints for CRUD operations.

4.1. Setting Up the MongoDB Connection
We will use Mongoose as the MongoDB ODM (Object Data Modeling) library to interact with the database. First, install the required dependencies:

npm install mongoose

Create a new file named `db.js` in the backend directory to set up the MongoDB connection:

// db.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log('Connected to MongoDB');
})
.catch((error) => {
console.error('Error connecting to MongoDB:', error);
});

Replace `’mongodb://localhost:27017/mydatabase’` with your MongoDB connection string, pointing to the desired database.

In your main backend file (e.g., `app.js` or `index

.js`), import the `db.js` file to establish the database connection when the server starts:

// app.js
const express = require('express');
const sentry = require('./sentry');
const db = require('./db');
const app = express();
// Other middleware and routes…
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});

With the MongoDB connection set up, we can now create the API endpoints for CRUD operations.

4.2. Creating the API Endpoints for CRUD Operations
For this case study, let’s assume we are building a simple API to manage user data, with endpoints for creating, reading, updating, and deleting user records.

Create a new directory named `models` in the backend directory, and within it, create a file named `user.js`. This file will define the Mongoose schema for our user model:

// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
age: {
type: Number,
required: true,
},
});
module.exports = mongoose.model('User', userSchema);

This schema defines a basic user model with `name`, `email`, and `age` fields.

Next, create a new file named `users.js` in the backend directory to handle the user-related API routes:

// users.js
const express = require('express');
const router = express.Router();
const User = require('./models/user');
// Route to create a new user
router.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).send(user);
} catch (error) {
res.status(400).send(error);
}
});
// Route to get all users
router.get('/users', async (req, res) => {
try {
const users = await User.find();
res.send(users);
} catch (error) {
res.status(500).send(error);
}
});
// Route to get a user by ID
router.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(500).send(error);
}
});
// Route to update a user by ID
router.patch('/users/:id', async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdates = ['name', 'email', 'age'];
const isValidOperation = updates.every((update) => allowedUpdates.includes(update));
if (!isValidOperation) {
return res.status(400).send({ error: 'Invalid updates!' });
}
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(400).send(error);
}
});
// Route to delete a user by ID
router.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(500).send(error);
}
});
module.exports = router;

In this file, we define the routes for creating, reading, updating, and deleting users. We use the `User` model from `user.js` to interact with the MongoDB database.

Now, let’s import the `users.js` router into our main backend file and set up the routes:

// app.js
const express = require('express');
const sentry = require('./sentry');
const db = require('./db');
const usersRouter = require('./users');
const app = express();
// Middleware
app.use(express.json());
// Routes
app.use(usersRouter);
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});

With this setup, our backend is now ready to handle CRUD operations with MongoDB.

5. Handling Errors and Capturing Events with Sentry

Now that we have our backend API set up, let’s integrate Sentry to track and capture errors and custom events.

5.1. Capturing Errors in the Backend
To capture errors, we can use a middleware function that intercepts all requests and responses, allowing us to handle any errors that occur during the request-response cycle. Create a new file named `errorHandler.js` in the backend directory with the following code:

// errorHandler.js
const Sentry = require('@sentry/node');
function errorHandler(err, req, res, next) {
Sentry.captureException(err);
// Log the error for debugging purposes
console.error(err);
res.status(500).json({ error: 'Something went wrong.' });
}
module.exports = errorHandler;

In this file, we use the `Sentry.captureException()` method to capture any errors that occur during the request-response cycle. Additionally, we log the error to the console for debugging purposes.

Next, import the `errorHandler` middleware in our main backend file (`app.js` or `index.js`) and use it as

the last middleware to capture errors:

// app.js
const express = require('express');
const sentry = require('./sentry');
const db = require('./db');
const usersRouter = require('./users');
const errorHandler = require('./errorHandler');
const app = express();
// Middleware
app.use(express.json());
// Routes
app.use(usersRouter);
// Error handling middleware
app.use(errorHandler);
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});

With this setup, any unhandled errors that occur during API requests will be captured by Sentry and logged into the console.

5.2. Capturing Custom Events
In addition to capturing errors, we can also capture custom events in our backend to gain insights into user interactions and application behavior. Custom events can be used to track specific actions, user behavior, or performance metrics.

For example, let’s capture an event when a new user is created:

// users.js
const express = require('express');
const router = express.Router();
const User = require('./models/user');
const Sentry = require('@sentry/node');
// …
// Route to create a new user
router.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).send(user);
// Capture a custom event for user creation
Sentry.captureEvent({
message: 'New user created',
user: user._id,
level: Sentry.Severity.Info,
});
} catch (error) {
res.status(400).send(error);
}
});

In this example, we use `Sentry.captureEvent()` to capture a custom event when a new user is created. The event includes the user’s ID, allowing us to link user data with specific events.

By capturing custom events, we can gain insights into user interactions, application performance, and usage patterns.

6. Enhancing User Experience with Sentry

In addition to error tracking, Sentry offers various features that can enhance the user experience and improve application performance.

6.1. Monitoring Performance with Transaction Tracing
Transaction tracing allows us to monitor the performance of specific API endpoints and track their response times and execution durations. This feature helps identify slow-performing routes and optimize application performance.

To enable transaction tracing, update the backend configuration to include the following:

// sentry.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_SENTRY_DSN',
tracesSampleRate: 1.0, // 100% sample rate for all transactions
});

With transaction tracing enabled, Sentry will automatically monitor the performance of all API endpoints and provide performance metrics in the Sentry dashboard.

6.2. Managing Release and Environment Data
Sentry allows developers to manage release and environment data, making it easier to track issues and errors specific to different versions or environments of the application.

To manage release and environment data, update the backend configuration as follows:

// sentry.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_SENTRY_DSN',
release: 'YOUR_APP_VERSION', // Replace with your application version
environment: 'production', // Set the environment (e.g., development, staging, production)
});

By providing the application version and environment, Sentry can group and organize errors and events accordingly.

7. Integrating Sentry with Frontend Applications

Integrating Sentry with frontend applications is as important as the backend, as it allows us to capture frontend errors and gain insights into user interactions. Sentry provides client SDKs for popular frontend frameworks like React, Angular, and Vue.js.

To integrate Sentry with a frontend application, install the appropriate Sentry SDK for your framework and configure it with the frontend Sentry DSN. Then, follow the SDK documentation to capture frontend errors and events.

8. Best Practices and Tips for Sentry Integration

To ensure the successful integration of Sentry into your Node.js backend project, consider the following best practices and tips:

- Use descriptive event messages and tags to categorize and filter events effectively.
- Configure different Sentry projects for different environments (e.g., development, staging, production) to keep data organized and isolated.
- Utilize breadcrumbs to track the user’s journey within your application and gain context around errors.
- Regularly review and analyze Sentry reports to identify recurring issues and prioritize bug fixes.

9. Conclusion

Integrating Sentry into your Node.js, Express.js, and MongoDB backend REST API project is a crucial step in building robust, error-free applications. With Sentry, you can capture and track errors, monitor application performance, and gain valuable insights into user interactions. By effectively managing and resolving issues, you can enhance the overall user experience and ensure the stability and reliability of your application.

Remember to utilize custom events and transaction tracing to monitor application-specific metrics and optimize performance. Additionally, integrate Sentry with your frontend applications to capture and track frontend errors as well.

By following the best practices and tips outlined in this article, you can maximize the benefits of Sentry and build more reliable and user-friendly web applications. Happy coding!

--

--

Saunak Surani
Widle Studio LLP

Passionate about technology, design, startups, and personal development. Bringing ideas to life at https://widle.studio