Using MedusaJS with MongoDB

A tutorial on how to integrate MedusaJS with MongoDB to create a robust and scalable database-driven application

MedusaJS is a Node.js framework for building scalable and modular applications. One of the key features of MedusaJS is its ability to work seamlessly with various databases, including MongoDB. In this tutorial, we will walk through the steps required to integrate MedusaJS with MongoDB to create a robust and scalable database-driven application.

Prerequisites

Before we get started, you’ll need to have the following installed on your computer:

  • Node.js (version 14 or higher)

  • MongoDB (version 4 or higher)

Creating a new MedusaJS project

First, let’s create a new MedusaJS project. Open your terminal or command prompt and run the following commands:

mkdir my-medusa-project
cd my-medusa-project
npm init -y
npm install --save medusa

This will create a new directory called “my-medusa-project”, initialize a new npm package, and install the MedusaJS framework.

Connecting to MongoDB

Next, we need to set up a connection to our MongoDB database. Create a new file called “database.js” in the root directory of your project and add the following code:

const mongoose = require('mongoose');

const connect = async () => {
  try {
    await mongoose.connect('mongodb://localhost/my-database', {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log('Connected to MongoDB');
  } catch (error) {
    console.error('Error connecting to MongoDB:', error);
  }
};

module.exports = {
  connect,
};

This code sets up a connection to a MongoDB database called “my-database” running on your local machine. Make sure to replace “my-database” with the name of your own MongoDB database. We’re using the Mongoose library to interact with MongoDB, which provides a simple and intuitive way to work with MongoDB from Node.js.

To use this code, we need to call the connect() function somewhere in our application. We can do this in the main file of our project (e.g. "index.js"):

const { connect } = require('./database');

connect();

This will connect to the MongoDB database when we start our application.

Defining a schema and model

Now that we have a connection to our MongoDB database, let’s define a schema and model for our data. Create a new file called “product.js” in a new directory called “models” and add the following code:

const mongoose = require('mongoose');

const schema = new mongoose.Schema({
  name: { type: String, required: true },
  price: { type: Number, required: true },
});

const model = mongoose.model('Product', schema);

module.exports = {
  schema,
  model,
};

This code defines a schema for a product, with a name and a price. We’re also creating a model for this schema using Mongoose’s model() function. The model() function takes two arguments: the name of the collection in the database (which is "products" by default), and the schema we just defined.

Using the model in our application

Now that we have a model for our product data, let’s use it in our application. Create a new file called “products.js” in a new directory called “routes” and add the following code:

const { Router } = require('medusa');
const { model: Product } = require('../models/product');

const router = new Router();

router.get('/products', async(req, res) => {
try {
const products = await Product.find();
res.json(products);
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Internal server error' });
}
});

module.exports = router;

This code defines a new route that handles GET requests to “/products”. When a user makes a request to this route, the function defined in the second argument will be called. This function uses the find() method on our Product model to retrieve all products from the database, and returns them as a JSON response.

We can now import this route in our main file (“index.js”) and add it to our application:

const { Medusa } = require('medusa');
const { connect } = require('./database');
const productRoutes = require('./routes/products');

const app = new Medusa();

app.use(productRoutes);

connect()
  .then(() => {
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
  })
  .catch((error) => {
    console.error('Error starting server:', error);
  });

This code creates a new Medusa application, sets up our product routes, and starts listening on port 3000. The connect() function is called to connect to the MongoDB database before starting the server.

Testing the application

Finally, let’s test our application to make sure everything is working as expected. Open your terminal or command prompt and run the following command:

npm install --save-dev supertest

This will install the supertest library, which we can use to write automated tests for our application.

Create a new file called “products.test.js” in a new directory called “tests” and add the following code:

const request = require('supertest');
const { Medusa } = require('medusa');
const { connect } = require('../database');
const productRoutes = require('../routes/products');

describe('Products API', () => {
  let app;

  beforeAll(async () => {
    await connect();
    app = new Medusa();
    app.use(productRoutes);
  });

  afterAll(async () => {
    await new Promise((resolve) => setTimeout(resolve, 500)); // workaround for jest open handle error
    await app.close();
  });

  describe('GET /products', () => {
    it('returns all products', async () => {
      const response = await request(app).get('/products');
      expect(response.status).toBe(200);
      expect(response.body).toEqual([]);
    });
  });
});

This code defines a test suite for our product routes. The beforeAll() function is called before any tests are run, and sets up our Medusa application with our product routes. The afterAll() function is called after all tests are run, and closes the application. The describe() and it() functions are used to define test cases.

Run the tests by running the following command:

npx jest tests/products.test.js

This will run the tests and output the results in your terminal or command prompt.

Conclusion

In this tutorial, we walked through the steps required to integrate MedusaJS with MongoDB to create a robust and scalable database-driven application. We set up a connection to MongoDB, defined a schema and model for our data, and used that model in our application to handle CRUD operations. We also wrote automated tests to ensure our application is working as expected. With this knowledge, you should be able to build your own database-driven applications using MedusaJS and MongoDB.