Gajanand Sharma
Writing
npmmongodbnodejstypescript

Creating a Reusable Database Schema Management NPM Package: A Comprehensive Guide

In a microservice architecture, each service typically defines its own database schema and logic. This approach often leads to:

·9 min read·

Crafting a Reusable Database Schema Management NPM Package for Microservices | NodeJs | MongoDB 🚀


Please Note: Advanced Content Ahead 🚨

This blog is best suited for advanced users familiar with transitioning from monolithic architectures to microservices. A good understanding of Node.js and MongoDB is essential. It’s tailored for those already versed in these technologies and architectural concepts.


Tada the Problem 😒

In a microservice architecture, each service typically defines its own database schema and logic. This approach often leads to:

Our Solution ⚙️

Centralized Database Schema Management Plugin 🌐

We create a plugin that offered a centralized solution to efficiently manage database schemas across multiple microservices. Key features include:

So let’s jump into the solution, here I am going to give you a walkthrough and approach with all necessary template which you can use and modify for your use case.

Let’s get started 😉

Implementation Steps 👣

1. Setting Up the GitHub Repository 🏗️

2. Building and Developing Locally 💻

perl
{
  "name": "@{Your_GitHub_username}/{package_name}",
  "version": "1.2.0",
  "description": "A package for MongoDB model schema definitions and connection management",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/{Your_GitHub_username}/{package_name}.git"
  },
  "keywords": [
    "mongodb",
    "mongoose",
    "schema",
    "model",
    "database"
  ],
  "author": "Author ",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/{Your_GitHub_username}/{package_name}/issues"
  },
  "homepage": "https://github.com/{Your_GitHub_username}/{package_name}/#readme",
  "dependencies": {
    "mongoose": "^5.13.7",
    "validator": "^13.0.0",
    "bcryptjs": "^2.4.3"
  },
  "devDependencies": {
    "jest": "^27.0.6"
  },
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/{your_org_or_username}"
  }
}
java
npm login --scope=@YOUR_GITHUB_USERNAME --registry=https://npm.pkg.github.com

3. Structure of the Package 📚

markdown
root/
    - index.js
    - package.json
    - .gitignore
    - Readme.md
    - models/
        - plugins/
        - sub-folder/
            - model1.model.js
javascript
const mongoose = require('mongoose');
const models = require('./models');
 
class DatabaseService {
    constructor(uri, options = {}) {
        this.uri = uri;
        this.options = options;
        this.models = {};
        this.loadModels();
    }
 
    async connect() {
        try {
            await mongoose.connect(this.uri, {
                ...this.options,
                useNewUrlParser: true,
                useUnifiedTopology: true
            });
            console.log('Connected to MongoDB successfully');
            this.loadModels();
        } catch (error) {
            console.error('Error connecting to MongoDB:', error.message);
            throw error;
        }
    }
 
    loadModels() {
        Object.keys(models).forEach((key) => {
            this.models[models[key].name] = models[key].model;
        });
    }
 
    getModel(modelName) {
        if(!this.models[modelName]) {
            throw new Error(`Model ${modelName} not found`);
        }
 
        return this.models[modelName];
    }
}
 
module.exports = DatabaseService;
javascript
const mongoose = require('mongoose');
const { toJSON, paginate } = require('./plugins');
 
const modelSchema = mongoose.Schema({
    // Your schema here
}, {
   timestamps: true,
    strict: false,
});
 
modelSchema.plugin(toJSON);
modelSchema.plugin(paginate);
 
const Model1 = mongoose.model('Model1', modelSchema);
module.exports = {
    name: 'Model1',
    model: Model1
};
javascript
const fs = require('fs');
 
const UTILITY_FOLDERS = Object.freeze([
    'plugins',
]);
 
const exportObject = {};
 
const getExports = (folderName) => {
    const files = fs.readdirSync(folderName);
 
    files.forEach((file) => {
        if(file === 'index.js' || UTILITY_FOLDERS.includes(file)) return;
 
        const stat = fs.lstatSync(`${folderName}/${file}`);
        if(stat.isDirectory()) {
            getExports(`${folderName}/${file}`);
        } else {
            const fileName = file.split('.')[0];
            exportObject[fileName] = require(`${folderName}/${file}`);
        }
    });
 
    return exportObject;
};
 
module.exports = getExports(__dirname);

4. Registering and Publishing the Package 🚢

sql
git add .
git commit -m "Initial package setup"
git push
npm publish

That’s it for the building and publishing part of our NPM package. We’ve covered how to set up a GitHub repository, develop the package locally, structure it properly, and finally, register and publish it on the NPM registry. This process ensures that our database schema management tool is not only well-organized but also easily accessible for integration into various projects.

Now you repo should look like this

Consuming the Package 🍴

Now that our package is up and running, let’s dive into how to effectively use it in your microservices architecture. This part of the guide will walk you through the steps to integrate and utilize the package in real-world applications, ensuring that you can leverage its full potential for efficient and consistent database schema management across your services.

1. Setting up .npmrc for Package Consumption 🔧

To use our package, you first need to configure your project to consume packages from GitHub Packages. This is done by setting up an .npmrc file in your project root:

  1. Create a .npmrc file in your project root 📁
  2. Add the following line to specify your GitHub package registry 🎛️
ruby
# Set the registry for scoped packages
@launchpadapps-au:registry=https://npm.pkg.github.com/
 
# Authentication for GitHub Packages (replace with your actual token for private packages)
//npm.pkg.github.com/:_authToken=YOUR_PERSONAL_ACCESS_TOKEN

2. Importing the Package in package.json 📦

perl
"dependencies": {
  "@Your_Github_Username/your-package-name": "^1.2.0"
}

3. Installing the Package with npm install 🧑‍💻

With the package added to your package.json, run npm install in your terminal. This command will install the package along with its dependencies into your project 👐.

4. Using the Package in Your Code ✍️

Now that the package is installed, you can start using it in your application. Here’s an example of how you might do this:

  1. Import the package at the beginning of your JavaScript file ⬇️
javascript
const DatabaseService = require('@Your_Github_Username/your-package-name');

2. Create an instance of the service 🏛

csharp
const dbService = new DatabaseService('your-mongodb-uri', { /* options */ });

3. Connect to your database and use the models 📩

javascript
dbService.connect()
  .then(() => {
    const User = dbService.getModel('User');
    // Use the User model for database operations
  })
  .catch(err => console.error('Database connection error:', err));

This section covered the necessary steps to consume the newly created NPM package in your project. By setting up .npmrc, adding the package to your package.json 🤗

Additional Steps for Local Debugging 🔍

Local debugging is crucial before you publish or use your package in a production environment. npm link is a powerful tool that allows you to test and debug your package locally. Here's how to use it:

1. Linking the Package Locally 🕵️‍♂️

bash
npm link

2. Linking the Package in Your Project 📌

perl
npm link @Your_Github_Username/your-package-name

3. Testing and Debugging 🔭

4. Unlinking the Package ♻️

Once you’re done with local testing and debugging, it’s important to unlink the package:

Unlinking from Your Project 🔻

perl
npm unlink @Your_Github_Username/your-package-name

Removing the Global Link 😌

bash
npm unlink

Summary and Key Takeaways 📝

This comprehensive guide has walked you through the journey of creating, publishing, consuming, and debugging a reusable database schema management NPM package tailored for microservice architectures. Key points to remember:

🎯 Centralization is Key:

🤝 Smooth Integration:

✅ Local Debugging:


Join the Conversation! 💬

We hope you found our journey to a more efficient deployment process inspiring and informative. But the conversation doesn’t end here! We’d love to hear from you and learn about your experiences with deployment, troubleshooting, and collaboration.

Share Your Story 📢

Have you encountered deployment challenges similar to ours, or do you have your own unique experiences to share? Whether it’s a deployment triumph or a troubleshooting tale, your story can provide valuable insights to the community.

Ask Questions ❓

If you have questions about the Cloud Run setup, Docker deployment, or any other topic covered in this blog, don’t hesitate to ask. I and fellow readers are here to help you find solutions.

Connect with Us 🌐

Join us on social media, where we regularly share tips, updates, and insights about web development and deployment. Follow us on Twitter, LinkedIn, or Facebook to stay connected with our growing community of developers.

Feedback and Suggestions 📝

We value your feedback! Is there a specific topic you’d like us to explore in future blogs? Do you have suggestions on how we can improve our deployment process even further? Let us know; your input shapes the content we create.

Stay Tuned for More 📅

Don’t miss out on our future blog posts! Subscribe to our newsletter or follow our blog for the latest updates, tutorials, and stories from the world of web development and deployment.

Thank you for joining us on this deployment journey, and we look forward to engaging with you in the comments, on social media, and in future blog posts. Together, we can make deployment easier and more efficient for everyone! 🚀🌐

Written by Gajanand Sharma

Building AI-powered backend systems, automating business operations, and shipping products.