Writing a Basic Web Server – Node Style

Towards the end of April I got increasingly frustrated with the state of the ASP.NET vNext and Visual Studio tools. Functionality that I wanted was in the dev branch but not available outside of the dev branch. Since the dev branch was full of dragons (is it my code or the alpha quality of the code?), I decided to do something different.

How about writing my entire application in node?

My requirements to do this are as follows:

  1. I need to be able to run a small web server
  2. I need to be able to handle templated views with server-side code
  3. I need to be able to do social authentication
  4. I need to be able to use an MVC architecture
  5. I need to be able to provide a Web API
  6. I need to be able to publish a node app to Azure
  7. I need to be able to edit node applications in Visual Studio 2015

I figured this would also give me an insight into the differences in development between node and ASP.NET – aside from the obvious Javascript vs. C# piece. So, call this an investigation.

Step 1 – Install Node

Installing node on Windows 10 is actually remarkably easy. Go to https://nodejs.org/ and click on the big green button that says Install Node. It will download an installer. Run the installer and it will install node in C:Program Filesndoejs. It also installs npm at the same time and adds it to the Path for you. At the end, you should be able to run node -v to check it out:

blog-code-0515-1

If you get something like “Command not found”, then it’s gone wrong. Start over.

Step 2 – Generate a Skeleton App

My next step is to create some sort of skeleton app. There are methods of generating much more functional skeleton apps – akin to the sample projects in Visual Studio. Anyone who has been reading my blog for a while realizes that’s not how I roll. I like to start from scratch.

I am uploading my work to GitHub, so I created a new GitHub repository called node-stuff. When creating the GitHub repository, I selected a .gitignore for node. I then cloned that repository to my machine with this:

blog-code-0515-2

Looking at the .gitignore, it handles runtime, jscover, grunt, and npm files. It’s a good starter.

Next, create a directory for the project and run npm init. npm init produces a basic package.json file for me. The package.json file describes my project so that npm can restore packages, build the application or whatever I want it to do. It’s about as much scaffolding as I need.

blog-code-0515-3

Step 3 – Add a web server to the app

I did a little bit of research and quickly found that just about everyone uses Express as their web server component. Express is described as a minimalist web framework. It’s relatively easy to get along with and has good documentation.

I just want to be serving “something” at this stage in the app. I actually don’t care about the content. It’s about the network communication. I need to add the library to my project. This is done via npm install --save, like this:

blog-code-0515-4

npm kindly installs all the dependencies as well. Now for some editing. I am using atom as my editor – it’s free and very Javascript friendly. I told npm init that I wanted my main application to be in index.js. Based on the Express Getting Started guide, here is what I put in there:

var express = require("express");
var app = express();

app.get("/", function(req, res) {
  res.send("Hello World!");
});

var server = app.listen(3000, function() {
  var port = server.address().port;
  console.log("Listening on http port %d", port);
});

Run it like this:

blog-code-0515-5

If you are running on Windows, you may be requested to allow the server to listen on the port. Yay for security! Browsing to http://localhost:3000 produces a nice small text document that says Hello World!

Press CTRL-C to stop the web server.

Step 4 – Provide a Client WebApp area

I generally want to split my applications into two areas – a Web API that is prefixed by /api and a client web application that is prefixed by /client. Let’s ignore the Web API for now and concentrate on the Client area. First off, make a ./client directory and put a simple HTML file called index.html in it. I’m not going to show these off, but trust me – the file is there in my repository.

Express is very simple though. You need to tell it everything. In this case, I need to tell Express that the files in /client are to be served as-is. In the Express Getting Started guide there is a whole page on static files. That makes it easy. I altered my index.js like this:

var express = require("express");
var app = express();

// Anything under /client is served as a static file
app.use("/client", express.static("client"));

app.get("/", function(req, res) {
  res.send("Hello World!");
});

var server = app.listen(3000, function() {
  var port = server.address().port;
  console.log("Listening on http port %d", port);
});

It’s just a one-line edition. However, when you run node index.js now, you can browse to http://localhost:3000/client/index.html and pick up your HTML file.

Step 5 – Re-route the Home Page

What happens when you go to http://localhost:3000/? You get the small text Hello World! that I put in there originally. I want the /client/index.html page to come up. Since Express exposes the entire HTTP transaction to me, I can do some logic here. In this case I want to redirect to /client/index.html when the user asks for the home page. I can do this with this code:

var express = require("express");
var app = express();

// Anything under /client is served as a static file
app.use("/client", express.static("client"));

app.get("/", function(req, res) {
  res.redirect("/client/index.html");
});

var server = app.listen(3000, function() {
  var port = server.address().port;
  console.log("Listening on http port %d", port);
});

All I’ve changed here is the code inside the app.get method for the home page. Instead of serving up some content, I’m serving up a REDIRECT. The browser receives the redirect and then issues another GET for the new location.

That’s it for step 1. You can get the code from my GitHub Repository.