Picture of Brian Love wearing black against a dark wall in Portland, OR.

Brian Love

TypeScript: Declaring Mongoose Schema + Model

So, you’re on the TypeScript bandwagon and you want to use Mongodb and mongoose. Great! So, now you need to define your schema and model. So, what is a good TypeScript developer to do? Well, first we turn to npm to install the dependencies and declaration files. This took me awhile to get right, so I hope it saves you some time.

Getting Started

We’ll start by using npm to install mongoose and the TypeScript declaration files using the new @types definitions with TypeScript 2.

$ npm install mongoose --save
$ npm install @types/mongoose --save-dev
$ npm install @types/mongodb --save-dev

Interface

First, let’s create a public interface for our model. In this example I am going to be using a: User. I created a new file at src/interfaces/user.ts:

export interface IUser {
  email?: string;
  firstName?: string;
  lastName?: string;
}

This simply represents a user, and will be helpful when populating our mongodb collections.

Schema + Model

For the schema and model, I put both of these into a new file at src/schemas/user.ts:

import { Document, Schema, Model, model} from "mongoose";
import { IUser } from "../interfaces/user";

export interface IUserModel extends IUser, Document {
  fullName(): string;
}

export var UserSchema: Schema = new Schema({
  createdAt: Date,
  email: String,
  firstName: String,
  lastName: String
});
UserSchema.pre("save", function(next) {
  let now = new Date();
  if (!this.createdAt) {
    this.createdAt = now;
  }
  next();
});
UserSchema.methods.fullName = function(): string {
  return (this.firstName.trim() + " " + this.lastName.trim());
};

export const User: Model<IUserModel> = model<IUserModel>("User", UserSchema);

Let’s dig into what is going on here:

In Action

Ok, now let’s see this in action. I have a simple REST API for the user defined in an expressjs app. Here is the get() method that is routed to the /users/:id GET request.

/**
 * Get a user
 *
 * @class UsersApi
 * @method get
 * @param req {Request} The express request object.
 * @param res {Response} The express response object.
 * @param next {NextFunction} The next function to continue.
 */
public get(req: Request, res: Response, next: NextFunction) {
  //verify the id parameter exists
  const PARAM_ID: string = "id";
  if (typeof req.params[PARAM_ID] === "undefined" || req.params[PARAM_ID] === null) {
    res.sendStatus(404);
    next();
    return;
  }

  //get the id
  var id = req.params[PARAM_ID];

  //get authorized user
  this.authorize(req, res, next).then((user: IUserModel) => {
    //make sure the user being deleted is the authorized user
    if (user._id !== id) {
      res.sendStatus(401);
      next();
      return;
    }

    //log
    console.log(`[UsersApi.get] Retrieving user: {id: ${req.params.id}}.`);

    //find user
    User.findById(id).then((user: IUserModel) => {
      //verify user was found
      if (user === null) {
        res.sendStatus(404);
        next();
        return;
      }

      //send json response
      res.json(user);
      next();
    }).catch(next);
  }).catch(next);
}

Here is what I am doing in the get() method: