Published on

Understanding MVC with Angular, MongoDB, and NestJS: A Practical Guide

Authors
  • avatar
    Name
    Winston Brown
    Twitter

In modern web development, the Model-View-Controller (MVC) architectural pattern is a popular way to organize applications. It separates the application into three main components: the Model (data), the View (user interface), and the Controller (logic that connects data and UI). This structure makes code more modular, easier to maintain, and scalable.

In this article, we'll explore how the MVC pattern applies when using Angular as the front end, NestJS as the backend API, and MongoDB as the database. We'll demonstrate this with a practical example: a MathAPI that calculates the average of an array of numbers. We'll create an endpoint with NestJS to handle this functionality.

What is MVC?

The Model-View-Controller (MVC) design pattern organizes your application into three components:

  1. Model: Represents the data and the business logic. It can interact with a database, like MongoDB in our case, and perform operations like reading and writing data.
  2. View: This is the presentation layer, where the user interacts with the app. In our case, Angular is the front-end framework responsible for rendering UI elements and sending requests to the backend.
  3. Controller: Acts as a mediator between the Model and the View. It handles incoming requests from the View, manipulates the Model, and sends back the response.

How Does MVC Work in This Context?

1. Model (MongoDB)

In our application, the Model is backed by MongoDB. This NoSQL database will store the data (e.g., numbers or other mathematical input) that the backend uses. While MongoDB doesn’t follow a strict schema like relational databases, NestJS integrates well with MongoDB using libraries like Mongoose or TypeORM.

In this case, our model might look like this:

import { Schema, Document } from 'mongoose';

export const NumberSchema = new Schema({
  numbers: [Number],
});

export interface NumberDocument extends Document {
  numbers: number[];
}

This schema defines a structure for storing an array of numbers in the database.

2. Controller (NestJS API)

The Controller in NestJS processes HTTP requests and delegates operations to the Service. For example, in the /average endpoint of MathAPI, the controller accepts the numbers array and passes it to a service that calculates the average.

Here’s how this would look in the MathAPI:

import { Controller, Post, Body } from '@nestjs/common';
import { MathService } from './math.service';

@Controller('math')
export class MathController {
  constructor(private readonly mathService: MathService) {}

  @Post('average')
  calculateAverage(@Body('numbers') numbers: number[]): { average: number } {
    const average = this.mathService.calculateAverage(numbers);
    return { average };
  }
}

The controller receives the array of numbers and forwards it to the MathService, which contains the business logic to calculate the average.

3. View (Angular)

On the View side, Angular handles the user interface and interactions. It allows the user to input a series of numbers, sends a POST request to the NestJS API, and displays the result.

Here’s a simple example of how Angular might look:

// average.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-average',
  templateUrl: './average.component.html',
})
export class AverageComponent {
  numbers: number[] = [];
  result: number | undefined;

  constructor(private http: HttpClient) {}

  calculateAverage() {
    this.http.post<{ average: number }>('/api/math/average', { numbers: this.numbers })
      .subscribe(response => {
        this.result = response.average;
      });
  }
}

In this example, the Angular component sends the numbers array to the backend API and receives the calculated average. The result is then displayed on the page for the user to see.

Putting It All Together

To recap how these layers interact:

  1. View (Angular): The user enters an array of numbers. Angular sends the input to the /average endpoint of the backend API.
  2. Controller (NestJS): The controller in NestJS receives the request, passes the numbers to the service, and sends the result (average) back to Angular.
  3. Model (MongoDB): Although in this case, we don’t store the numbers permanently, the model can be used to log data or perform operations that involve persistent storage.

This separation of concerns (MVC) helps in keeping your code modular and maintainable, especially as your application grows in complexity.

Conclusion

In this article, we walked through the MVC pattern using Angular, NestJS, and MongoDB, along with a practical example of a MathAPI /average endpoint. This structure ensures that each part of the application has a clear responsibility, leading to cleaner, more maintainable code.

By following this pattern, you can scale your application easily, whether it's handling more complex data models with MongoDB, adding more features to the front end with Angular, or building more sophisticated APIs with NestJS.

If you want to dive deeper into the backend development with NestJS, check out my article on creating a MathAPI with a POST endpoint: 'Creating a Math API with NestJS: A Practical Guide to the /average Endpoint'.

Happy coding!