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.
First go to the seed project and fork it.
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.
To add controllers:
server/controllers
folder. Lets add server/controllers/newExample.ts
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: {}
});
}
}
init()
function.Defining a Route and the Controller to Use
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'
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);
}
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
server/models
. For this we will create server/models/newExample.ts
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);
NewExampleDto
.schema
object will define the schema/structure of the NewExample
model inside of Mongo.NewExampleModel
constant will be what we use to access the NewExample Document in Mongo to update, create, or get. //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
});
}
});
}
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.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.