Thursday, March 31, 2016

Empty TypeScript Files When Debugging

When developing TypeScript web apps in the browser, it uses a map file to load the TypeScript file that maps to a JavaScript file. You'll usually see something like this at the bottom of your JS files.

//# sourceMappingURL=app.js.map

Inside that map file is a bunch of JSON, including the name of the TS files that it maps to.

"sources":["app.ts"]

This causes the browser to go out and download the TS file so you can debug it in the browser developer tools.

Seems like every time I start a new project I run into the same problem. I go to debug my code, I open up the TS file in dev tools and it's empty. It takes me a minute then I say, "Oh yeah, I remember now!".

The problem is that IIS doesn't know how to serve TS files, so you have to tell it. All you have to do is go into the web.config file and add the following inside the system.webServer section:

  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".ts" mimeType="application/x-typescript" />
    </staticContent>
  </system.webServer>

This tells the server that whenever it sees a file extension of ".ts" that it's a TypeScript file. Now if you go back the browser and refresh you'll be able to see the contents of the mapped TS files.

Note: you can do this for any other file types IIS doesn't know about, such as audio/ogg. Any time the browser complains about not finding a file and you know the path is correct, it's probably because of the Mime type not being recognized.

Also note that you can do this within IIS too. Go to your website, open "Mime Types"and click Add to add it.

Tuesday, March 22, 2016

Creating a Node.js REST Service with TypeScript

In my last post I talked about the basics of creating a Node.js server app using TypeScript in Visual Studio. In this post I'll expand upon that to show how to create a RESTful web service that exposes an API to access CRUD operations for a "todo" web app.

Body Parser Middleware


We'll start where we left off in the previous post. In that post we added the Express package using npm. For this app we also need to add the Express body-parser module. This module is a middleware component for Express that parses the body of HTTP requests so we can get data that has been sent via a POST request. To add it right click on "npm" in the project tree, select "Install new npm Packages", then search for "body-parser" and install it.


Now we need the type definition file for body-parser so we get intellisense in our TypeScript files. We'll have to get that from the Node command line using "typings". Make sure you're in the project folder then execute the following:

> typings install body-parser --ambient --save

Now we can start to write our main module, app.ts and include body-parser.

import express = require("express");
let app = express();

import bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));

First we import express and create our app. Then we import body-parser and tell our app to use its urlencoded middlware component. This middleware takes incoming POST requests where the body uses x-www-form-urlencoded format and parses the form data into name/value pairs which can be accessed through the request.body object. We'll see more about that later.

The Data Model


Before we go any further we need to define our todo item model. So let's create a folder in our project called models and add a new TypeScript file called todoModel.js.

export interface ITodoItem
{
    id: number;
    name: string;
    created: Date;
}

let nextId = 1;

export class TodoItemModel implements ITodoItem
{
    public id: number;
    public created: Date;

    constructor(public name: string)
    {
        this.id = nextId++;
        this.created = new Date();
    }
}

Inside there we define an ITodoItem interface, then we define a TodoItemModel class that implements it. I like to have an interface for each model so that we don't always need to use the class, especially if we're getting objects from JSON.

Notice that the interface and class are exported so we can use them outside of the module. Notice also the variable named nextId. This is used in the constructor to create a unique ID for each todo item that is created. We don't want this variable to be visible outside of the module so we don't export it.

The Data Repository


Now we need a repository to save our todo items in. Let's create a folder called repositories and add a TypeScript file called TodoItemRepo.ts.

import models = require("../models/todoModel");

export interface ITodoItemRepo
{
    add(item: models.ITodoItem): void;
    remove(id: number): models.ITodoItem;
    findById(id: number): models.ITodoItem;
}

export class TodoItemList implements ITodoItemRepo
{
    private list: models.ITodoItem[] = [];

    public add(item: models.ITodoItem): void
    {
        this.list.push(item);
    }

    public remove(id: number): models.ITodoItem
    {
        for (let i = 0; i < this.list.length; i++)
        {
            if (this.list[i].id === id)
            {
                return this.list.splice(i, 1)[0];
            }
        }

        return null;
    }

    public findById(id: number): models.ITodoItem
    {
        for (let i = 0; i < this.list.length; i++)
        {
            if (this.list[i].id === id)
            {
                return this.list[i];
            }
        }
        return null;
    }
}

First we import our todo item model, then define an interface for our todo item repository. We need a way to add, remove and find items in the repository. Then we implement a repository for that interface called TodoItemList that merely stores the items in an array. In a real app our repository would probably interact with a database, but that's beyond the scope of this post.

Defining the Routes


Now that we have our model and a place to store our data we can create our routes. First thing we want to do is create a folder called routes and create a new TypeScript file called todoAPI.ts. This module will hold all of our routes and the implementation of those routes. By placing them in their own file we keep them out of our main file app.ts to keep it clean.

import express = require("express");
import models = require("../models/todoModel");
import repos = require("../repositories/todoItemRepo");

let todoList = new repos.TodoItemList();

export function initRoutes(app: express.Express): void
{
    app.get('/todo', list)
        .post("/todo", create)
        .get("/todo/:id", getById)
        .put("/todo/:id", update)
        .delete("/todo/:id", del);
}

function list(req: express.Request, res: express.Response): void
{
    res.status(200).json(todoList);
}

function create(req: express.Request, res: express.Response): void
{
    todoList.add(new models.TodoItemModel(req.body.name));
    res.status(200).json(todoList);
}

function getById(req: express.Request, res: express.Response): void
{
    let id = parseInt(req.params.id);
    let item = todoList.findById(id);
    if (item)
    {
        res.status(200).json(item);
    }
    else
    {
        res.status(400).send("Item not found: " + req.params.id);
    }
}

function update(req: express.Request, res: express.Response): void
{
    let id = parseInt(req.params.id);
    let item = todoList.findById(id);
    if (item)
    {
        item.name = req.body.name;
        res.status(200).json(item);
    }
    else
    {
        // Bad request
        res.status(400).send("Item not found: " + req.params.id);
    }
}

function del(req: express.Request, res: express.Response): void
{
    let id = parseInt(req.params.id);
    if (todoList.remove(id))
    {
        res.status(200).json(todoList);
    }
    else
    {
        // Bad request
        res.status(400).send("Item not found: " + req.params.id);
    }
}

First we import the model and repository modules. Then we create a new TodoItemList to hold our items. Next is the only function that will be visible outside of the module, initRoutes(). This function takes our app that we created in app.ts and adds the routes for our API to it.

All of the routes start with "/todo" and a few have "/:id" appended. By placing a colon at the beginning of a route part it tells the express router that this is a parameter. All route parameters will be map it to the request.params object. So in this case we should be able to access request.params.id.
Each route is mapped to a function that is defined in the module. Note that none of the handler functions are exported. They don't need to be because we are setting up the routes inside the module.
  • The list() function merely returns the todo list object.
  • The create() function first gets name of the new todo item from the request.body object using request.body.name (The body-parser middleware put it there for us). Then it creates a new instance of a TodoItemModel and adds it to the list. Finally it returns the updated list.
  • The getById() function gets the id parameter from the request.params and returns the matching todo item. If one isn't found it returns a 400 HTTP status.
  • The update() function gets the id of the item to update from the request.params and the new name of the todo item from the request.body object and updates it. Then it returns the item.
  • And finally the del() function gets the id of the item to delete from the request.params and removes the item from the list then sends back the updated list.

Starting the Service


That's it for our todo API! Now we need to go back into our main file, app.ts and tell it to use our routes and start the service. We add the following to that file:

import todoApi = require("./routes/todoApi");
todoApi.initRoutes(app);

let port = 8080;
let server = app.listen(port, () => console.log("Listening on port " + server.address().port));

First we import our todoAPI module, then call its initRoutes() function passing in our application. Then lastly we start the service by calling app.listen().

Let's go run it now and test it out. From the Node command line we start the service.

node app

We should get the message, "Listening on port 8080" if all went well. Now we need to test it.

Testing the API


In order to test our API we'll need a tool to test REST web services. We're not creating the front end as part of this post so we'll need another way to test it. I like to use the Postman extension in Chrome (http://www.getpostman.com/). It allows you to specify any REST verb as well as specify parameters in the body of the request.

First let's add a todo item. To do that we will set the verb to POST and use the URL: http://localhost:8080/todo. We also need to specify the todo item name in the body. We need to use x-www-form-urlencoded as the body type.



Now click the Send button and it adds a new item named Task1. It also returns the todo list which we see in the response body. That means it worked. Now let's test some other routes.

  • Set the verb to GET and call http://localhost:8080/todo. This will hit return the list of all items.
  • Set the verb to GET and call http://localhost:8080/todo/1. This will get the item with the id of 1.
  • Set the verb to PUT, add a name parameter to the request body, and call http://localhost:8080/todo/1. This will change the name of the item with id of 1.
  • Set the verb to DELETE and call http://localhost:8080/todo/1. This will delete the item with id of 1.

In this way you can play around with the todo service API adding, removing and changing todo items.

No we have a working web service with CRUD operations for managing a list of todo items. From here we could write a front end app that consumes these APIs. Look for a future post to implement that.

<jmg/>

Friday, March 18, 2016

Using TypeScript with Node.js

I've been putting off learning how to write a Node.js app long enough. So I decided that I wanted to learn by writing a REST web API service. I also wanted to write it using TypeScript so I could get static typing and intellisense to make it easier to learn.

I looked at a lot of tutorial out there and they all want to over complicate things. So I thought I would boil the process of creating a Node.js RESTful web API service and using TypeScript as the programming language. I'm using Windows and Visual Studio 2015 for this tutorial.

First thing you need is to install Node.js of course. That's not too difficult. Go to https://nodejs.org/ and download it.

You're also going to want to make sure you have the latest version of TypeScript for Visual Studio. Go to Tools > Extensions and Updates and search for TypeScript and install it.

Another great tool for VS that is going to make your life a whole lot easier is Node.js Tools for Visual Studio. NTVS is a free, open source plugin that turns Visual Studio into a Node.js IDE. You can also install it from Extensions and Updates.

Now let's create a project for our Node.js app. Assuming you've installed NTVS you can create a new project using one of the project templates that NTVS installed. For this example I used Blank Node.js Console App project.


Now that we have our project we need to define what npm packages our app depends on. We want to use Express (http://expressjs.com/), which is a web application framework that makes it easier to handle HTTP requests and responses. It also makes it easy to insert any middleware you want in your HTTP handling pipeline, such as logging and parsing message bodies. It's a really great framework for creating web apps.

To install it right-click on the "npm" item under the project in solution explorer and select Install New npm Packages. Search for express and install it. Now you'll see it in your list of installed packages.


Next we want to get the TypeScript type definition files for Express so we have intellisense. Unfortunately I couldn't find any way to do this from inside VS, so we're going to have to go to the node command line to do that. First thing we need is a package to help manage type definitions. There is a npm package called Typings for that (https://github.com/typings/typings). Install it from the command line like so:

> npm install typings --global

Now we can use Typings to fetch type definitions for our project. So first navigate to the project folder.

> cd \lab\MyWebApi

Then install all the type defs we need. Express uses the following typings:

> typings install dt~express --global --save
> typings install dt~serve-static --global --save
> typings install dt~express-serve-static-core --global --save
> typings install dt~mime --global --save

[Update: 2016-08-15] Previously this was using the --ambient parameter. However, this is now deprecated, use --global instead. Also, you must now prefix the module names with "dt~" so it knows the source is the Definitely Typed library.

This should have added a typings folder under our project folder with all of the typings. It also created a main.d.ts file in there. That's the only file we need to add to the project, so in VS go and include that file in the project.

That's it for setup. We are now ready to code. Open up the app.ts file and remove anything that's already in there. Then add the following:

import express = require("express");
let app = express();

This imports the express module so that we can use it. Then we use it to create a new express app and assign it to the app variable. Now we can set up some routes for our RESTful web API service. Let's add a GET route and set the route to "/api".

app.get("/api", (req, res) =>
    {
        res.status(200).json({ message: "api GET called!" });
    });

Here we are telling our app to watch for GET requests on the path /api and run the handler function when we get one. The handler function gets two parameters, the request and the response objects. Our handler function first writes to the response an HTTP status code of 200 (OK) then tells it to return some json. Pretty simple! In a real app we would get some kind of real data, but for now we're just making sure it works.

Now we need to start the server listening for requests. For that we add:

let port = 8080;
app.listen(port, () => console.log("Listening on port " + port));

This will start the server on port 8080. When it's ready it will display the message logged from the callback function. Now we can run it and see if it works. To start the app go back to the node command prompt and enter:

> node app

You should see the message "Listening on port 8080". Now open a browser window and go to: localhost:8080/api. You should get {"message":"api GET called!"}. That's it, you now have a RESTful service running in Node.

Now we can add any of the other REST verbs we want our service to support. Express supports all of the REST verbs. For example, if we want to add a handler for POST we can add the following:

app.post("/api", (req, res) =>
    {
        res.status(200).json({ message: "api POST called!" });
    });

To test anything other than GET requests you're going to have to use a Web API testing tool like Postman (http://www.getpostman.com/). I highly recommend it for testing web APIs.

Those are the basics for creating a RESTful web API service using Node.js in Visual Studio with TypeScript. Next time I'll show how to make the web service more modular so it's easier to maintain larger services.