TypeScript and the MEAN Stack: Getting started Part 2

Introduction

In my previous post, we got a brief idea on what TypeScript and the MEAN stack are. We installed the essential tools and put together a simple node/express application. Here, we will continue from where we left off, connecting the application to MongoDB.

Some Quick Housekeeping

Before we get started with hooking up the application with MongoDB, let’s make the following file and folder changes:

  1. Create new folder called app at the root level of the project.
  2. Move the routes and view folders to the app folder.
  3. Rename app.ts to server.ts.
  4. Rename index.ts and user.ts in the app/routes folder to indexRoutes.ts and userRoutes.ts respectively. Module dependencies should also be updated.
  5. Create a new folder called controllers in the app folder and add a new TypeScript file userController.ts to it.
  6. Create a new folder called models in the app folder and add a new TypeScript file userModel.ts to it.

The app folder should have the following structure:

image

Hooking up the application to MongoDB

We are going to create a simple entity and attempt to create and retrieve some instances, using MongoDB for persistence. There are quite a few ways to achieve this, but for the time-being, we are going to use mongoose.

Install mongoose

We can add mongoose via npm. After the package is retrieved, let’s get the mongoose definition file from the definitely typed repository and add it to Scripts/typings/mongoose.

Update server.ts

The module dependencies in server.ts should be as follows:

/*
 * Module dependencies.
 */
import express = require('express');
import routes = require('./app/routes/indexRoutes');
import user = require('./app/routes/userRoutes');
import http = require('http');
import path = require('path');
import mongoose = require('mongoose');

In the same file, we should add that we want to connect to the database:

/*
 * Main application entry file.
 * Please note that the order of loading is important.
 */
mongoose.connect('mongodb://localhost/mean-type-dev');
 
var app = express();

Create the schema and interface

For the purposes of this session, we will create a User entity with the field “name”. The file userModel.ts will contain the following:

import mongoose = require("mongoose");
 
export var userSchema = new mongoose.Schema({
    name: String
});
 
export interface IUser extends mongoose.Document {
    name: string;
}
 
export var repository = mongoose.model<IUser>("User", userSchema);

There is a bit of duplication here. Mongoose requires the use of schema definition code for data validation, type casting, etc. In TypeScript, we also need to define interfaces that extend mongoose documents. This is not ideal, and it would obviously be better if we can get the two aspects working better together. This is a topic that would require further investigation. For the time being, this will have to work.

Create the controller

My aim is to keep the controller as the entry point of the web requests and to maintain whatever application logic is needed. The controller will take the request, process the data in some meaningful way via the repository, and depending on the result, provide a suitable response.

So userController.ts will look like this:

import express = require("express");
import mongoose = require("mongoose");
import userModel = require("../models/userModel");
 
import IUser = userModel.IUser;
import repository = userModel.repository;
 
export function createUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.create({ name: userName }, (error) => {
        if (error) {
            res.send(400);
        } else {
            res.send("user " + userName +" created");
        }
    });
}
 
export function retrieveUser(req: express.Request, res: express.Response) {
    var userName = req.params.name;
 
    repository.findOne({ name: userName }, (error, user) => {
        if (error) {
            res.send(400);
        } else {
            res.send("user with name " + user.name + " retrieved");
        }
    });
}

Update routes

To keep the aforementioned idea, the routing files should be kept as simple as possible. This was kept in mind for the new operations in the controller that need to be exposed via userRoutes.ts:

import express = require("express");
import controller = require("../controllers/userController");
 
/*
 * User Routes
 */
export function list(req: express.Request, res: express.Response) {
    res.send("respond with a resource");
};
 
export function create(req: express.Request, res: express.Response) {
    controller.createUser(req, res);
};
 
export function read(req: express.Request, res: express.Response) {
    controller.retrieveUser(req, res);
};

Back on server.ts, let’s update the routing code:

app.get('/', routes.index);
app.get('/users', user.list);
app.get('/users/:name', user.read);
app.post('/users/:name', user.create);

Tools

We’re almost set to give it a spin. Let’s go ahead and grab some more tools that will help us with testing:

  • Any REST client. I use Postman and it suits my needs.
  • Any MongoDB management tool. My preference here is Robomongo.

Some tests

Now we can run the application and fire up a REST client. Again, keeping things simple, let’s go ahead and add the URL below and setting the method to POST. Sending the request will give us a response that the user was created:

image

Now that we created a user, we can also retrieve with the same URL and with the GET method:

image

So far, so good. Let’s just check to see that we do have something stored in our database. Using Robomongo, we add our local connection, which should appear automatically in the connections dialog:

image

The database “mean-type-dev” should be found, along with the collection users. Looking at the users collection, we find a user, which is in fact the user we created:

 

image_thumb.png

So there you have it. We now have a node application that can play nicely with MongoDB, with everything written up in TypeScript.

Conclusion

Today we were able to hook up our application with MongoDB via mongoose and perform some basic database operations. My next post will focus more on the client side, digging into angular.

Cheers!

Advertisements

10 thoughts on “TypeScript and the MEAN Stack: Getting started Part 2

  1. Thanks for the tutorial! It helped me a lot!

    Here are some problems I had, I hope this will help a few people:
    – Renaming is a little bit of a pain in Visual Studio 2013 Update 3
    – I had to change the line “app.set(‘views’, path.join(__dirname, ‘views’));” to ”
    app.set(‘views’, path.join(__dirname, ‘app/views’));”
    – I had to use node.d.ts from https://github.com/borisyankov/DefinitelyTyped instead the one from Microsoft (under Scripts/typings)
    – The provided source code has some mistakes:
    – userModel.ts: “export var repository = mongoose.model(“Userma);” should be “export var repository = mongoose.model(“UserSchema”, userSchema);”
    – userController.ts: “res.send(“useruserName +” created”);” should be “res.send(“useruserName: ” + userName);”
    – server.ts / app.ts: should be
    “app.get(‘/’, routes.index);
    app.get(‘/users’, user.list);
    app.get(‘/users/:name’, user.read);
    app.post(‘/users/:name’, user.create);”
    – To run it under VS I had to rename “server.ts” to “app.ts”

    Cheers and Thanks
    Michael

    • Hi Michael,

      Thanks for your comments and your feedback. I had a look at the code ad you’re completely right about the needed changes. Much appreciated!

      Cheers,

      Dino

    • 1) Renaming what is not clear.
      2) I couldn’t find “app.set(‘views’, path.join(__dirname, ‘views’));”
      3) The link for DefinitelyTyped repository is changed. Also, there is no need to download it from there. VS 2015 already have it by default. We can also use npm modules to directly download type definitions.
      4) In userController.ts, it is “res.send(“user name: ” + userName + “created”);”

    • It should be “export var repository = mongoose.model(“users”, userSchema);” “export var repository = mongoose.model(“UserSchema”, userSchema);”, if we go by the image posted

  2. Thanks for sharing. I started my project with the MEAN stack using native mongodb driver, and got it in a reasonable state. Then, I moved to mongoose. Now, I’m trying using TypeScript, and realize that all the objects are kind of duplicated, one for typescript class and the other for mongoose schema. Is there a way to combine them? For example, use schema in class or vice versa?

  3. 1) Renaming what is not clear.
    2) I couldn’t find “app.set(‘views’, path.join(__dirname, ‘views’));”
    3) The link for DefinitelyTyped repository is changed. Also, there is no need to download it from there. VS 2015 already have it by default. We can also use npm modules to directly download type definitions.
    4) In userController.ts, it is “res.send(“user name: ” + userName + “created”);”

  4. Mongoose type definitions to be added using “tsd install mongoose –save” from command promt in “Scripts” folder of solution
    tsd to be installed using “npm i tsd -g” as given in https://www.npmjs.com/package/tsd

    Install es6-shim npm package using context menu using NTVS or cmd
    Also add es6-shim type definition using the steps shown above

  5. 1) Mongoose type definitions to be added using “tsd install mongoose –save” from command promt in “Scripts” folder of solution
    2) tsd to be installed using “npm i tsd -g” as given in https://www.npmjs.com/package/tsd
    3) Install es6-shim npm package using context menu using NTVS or cmd
    4) Also add es6-shim type definition using the steps shown above

  6. It should be “res.send(“user with name ” + user.name + ” retrieved”);” instead of “res.send(“user with name ” + user.name + ” retrieved”);”

  7. It should be “res.send(“user with name ” + userName + ” retrieved”);” instead of “res.send(“user with name ” + user.name + ” retrieved”);”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s