04 August 2017 Nodejs and Mongo using some MEAN Typescript

The Why

What server side Framework should I use on side projects?

At work, I don’t always get to choose which languages or frameworks I get to develop in. For example, for the last year and half I have been using Typescript and Angular 2 on the client side with .NET web services written in C# on the server side.

So during the last year and half I have come to really enjoy Angular 2 and Typescript. However when developing a project on the side, I usually don’t like all the overhead that comes along with .NET web services. I also tend to lean toward something that I can get up and running quickly. I have usually leaned toward something like Ruby on Rails to develop my server side APIs.

Using the same framework and languages all the time can get boring. So I thought I would look into a new framework to play around with. As I mentioned I have come to love javascript, more specifically Typescript. Due to this I thought I would look into using the MEAN stack, while writing my NodeJS code with Typescript. With NodeJS I get a lot of the speed and quick development time that I have come to enjoy with Rails, while also getting other benefits such as web sockets, less memory utilization, and speed. Then with Typescript I get the sugar coating that makes javascript look and feel like a real Object Oriented language, along with the added security of typing and compilation errors.

So now that I know I wanted to use NodeJS and Typescript, I went about looking for a quick and easy tutorial on how to get up and running with both. While I found nice seed projects and such for doing NodeJS there was very little on how to incorporate Typescript and use it with NodeJS. This is where I will hopefully save you some time.

If you are looking to learn specifics about the NodeJS framework, how to write in Typescript, or details about Mongo this post will not help you. I will show you how to get up and running with NodeJS and the overall MEAN framework using Typescript.

The How To

First go to the seed project and fork it.


Project Structure

If you notice, the project is divided into two parts. The client and the server as follows.

- client
  - app
    - shared
      -services
        - http.client.service.ts
    - app.component.html
    - app.component.ts
    - app.module.ts
    - app.routing.ts
    - main.ts
    - polyfills.ts
    - rxjs-operators.ts
- server
  - server
    - bin
      - www
    - controllers
      - index.ts
      - newExample.ts
    - models
      - newExample.ts
    - views
      - index.hbs
    - app.ts
- tsconfig.json
- package.json
- webpack.config.common.js
- webpack.config.dev.js
- webpack.config.prod.js

Since we are using typescript on both the client and server you will notice we only have one tsconfig.json and package.json file. The package.json file will hold the commands to build and run the project. Looking into the package.json you will see two commands used to run the application.

npm build

This will use webpack to compile your client typescript code and then move it to the server/public/js/app folder. This is so we can serve our Angular code from the web app server’s public directory.

The other command:

npm start

This will use the npm packages ts-node to compile our typescript code on the server side and nodemon to launch the web application.

I am not going to get into the structure of the client side for this post, but if you wish to learn more on Angular 2 feel free to look at another blog post I wrote here on Angular 2.

On the server side we have four folders which are pretty self explanatory. First the bin directory which will contain the www file that creates and launches the node server. The controllers directory which will hold all of our controllers (aka. routes in the Node world). Next the models directory which will hold our DTO’s to talk with both the JSON on the front end and the Mongo Documents on the DB side. Last, the views directory which will hold the entry point to our application and launching of the Angular application.

Now we will start looking into how we utilize Typescript inside NodeJS to build our Models and Controllers.


Node Controllers and Models in Typescript

To add controllers:

  • You will create a new controller in the server/controllers folder. Lets add server/controllers/newExample.ts
  • Your controller should have the following flow:
import { NextFunction, Request, Response, Router } from 'express';

export class NewExampleController {

  static init(): Router {
    console.log('[NewExampleController::init] Creating index route.');
    let router = Router();

    let controller = new IndexController();
    router.get('/:id', controller.show);
    router.post('/', controller.post);

    return router
  }

  show(req: Request, res: Response, next: NextFunction) {
    console.log('[NewExampleController::index]');

    res.status(200).json({
      message: 'New Example Controller Index',
      obj: {}
    });
  }

  post(req: Request, res: Response, next: NextFunction) {
    console.log('[NewExampleController::post]');

    res.status(200).json({
      message: 'New Example Controller Post',
      obj: {}
    });
  }
}
  • As you can see you will add all the routes for this controller in the init() function.
  • You will then define all the methods to handle the control flow of a route through the application. Here that is the show and post methods.
  • I believe in keeping a restful feel to an application so a controller really should only contain get, post, put, etc http protocols.

Defining a Route and the Controller to Use

  • In server/app.ts you will add a call to your new controller by importing it at the top of the file import { NewExampleController } from './controllers/newExampleController'
  • You will then go to the api method in server/app.ts and add the initialization of your new route and the controller it will flow through.
  private api() {
    let newExampleController = NewExampleController.init();
    this.app.use('/api/new-example', newExampleController);
  }
  • This will now make a Get call to http://localhost:3000/api/new-example/:id flow through the show method in the NewExampleController and a Post call to http://localhost:3000/api/new-example/ flow through the post method.

How to make and use a Model

  • You will create a new model in server/models. For this we will create server/models/newExample.ts
  • Your model should look like the following.
import { Document, Schema, model } from 'mongoose';

export class NewExampleDto {
  name: string;
  allowed: boolean;

  constructor(data: {
    name: string,
    allowed: boolean
  }) {
    this.name = data.name;
    this.allowed = data.allowed;
  }
}

let schema = new Schema({
    name: {type: String, required: true},
    allowed: {type:Boolean, required: true}
});

export interface NewExampleDocument extends NewExampleDto, Document { }

export const NewExampleModel = model<NewExampleDocument>('NewExample', schema);
  • JSON will get moved from front end to back end and visa versa by using the DTO, here the NewExampleDto.
  • The schema object will define the schema/structure of the NewExample model inside of Mongo.
  • The NewExampleModel constant will be what we use to access the NewExample Document in Mongo to update, create, or get.
  • Here is how a Model would be used. Lets go into the NewExampleController’s show and post method for this practice:
  //Lets say http://localhost:3000/api/new-example/20 is called
  show(req: Request, res: Response, next: NextFunction) {

    let NewExampleModel.findOne(req.params.id, (err, data) => {
      if (!err) {
        let newExample = new NewExampleDto(data);

        return res.status(200).json({
          obj: newExample
        });
      }
    });
  }

  //Lets say http://localhost:3000/api/new-example/ is called
  post(req: Request, res: Response, next: NextFunction) {
    let newExample = new NewExampleDto(req.body);

    NewExampleModel.create(, (err, data) => {
      if (!err) {
        return res.status(201).json({
          message: 'New Example created',
          obj: result
        });
      }
    });
  }
  • Here the NewExampleModel is used to find or create a NewExample record in the Mongo DB. So the Model will be what we use to talk with Mongo.
  • We use the NewExampleDto to convert the JSON into something the Model can digest, as well as converting the NewExample record in Mongo into JSON the client side can digest.

You can now start building out routes and models in your MEAN stack with typescript. Once again the seed project can be found here.

Dustin Kocher · @DustinKocher · Senior Software Engineer