Sergio and the sigil

Language Envy - Juicy, a simple webserver

Posted by Sergio on 2009-04-13

Many times when I'm writing JavaScript code with Ajax calls I don't have an URL to call and get the data yet. Or sometimes I have an URL that gives me valid data and I need to test the code against invalid data or some other variation that I don't have handy.

WEBrick

In these situations, instead of creating a temporary ASP.NET application, I learned to love using Ruby and the adorable simplicity of WEBrick. Imagine that I needed an URL that simulated latency on the server.

require 'webrick'
include WEBrick

server = HTTPServer.new( :Port => 2000 )

server.mount_proc("/getData"){|req, res|
  res.body = "{result: 'ok', accountId: 123}"
  res['Content-Type'] = "application/json"
  delay = req.query['delay'] || "0"
  sleep(delay.to_i)
}

trap("INT"){ server.shutdown }
server.start

After running the script I can open use the URL http://localhost:2000/getData?delay=5 in my Ajax call and, after a delay of five seconds, the JSON string {result: 'ok', accountId: 123} will be returned. The server will stay there, in a console window, running until I kill it with CTRL+C.

I could add more mount points on that server for as many test URLs as I wish. I find this incredibly practical.

I wish there was something as simple in .NET

Well, I couldn't find anything as easy in .NET. The few offerings I found were not as straight forward. Some of the alternatives are distributed in .msi files, which makes them less convenient, especially for integration testing or JavaScript unit testing (which is my end goal.)

Hello Juicy

Envy sometimes makes you move forward. I played around with sockets and the HTTP protocol and ended up with a library that looks promising. See that same code written using the Juicy.DirtCheapDaemons.Http.HttpServer class, a.k.a. the Juicy Web Server.

using System;
using System.IO;
using System.Threading;
using Juicy.DirtCheapDaemons.Http;

  class Program
  {
    static void Main(string[] args)
    {
      HttpServer server = new HttpServer{ PortNumber = 2000 };
      server.Start();

      server.Mount("/getData", 
        (req, resp) =>
          {
            resp.Output.Write("{result: 'ok', accountId: 123}");
            resp["Content-Type"] = "application/json";
            var delay = int.Parse(req.QueryString["delay"] ?? "0");
            Thread.Sleep(1000 * delay);
          }
      );

      Console.WriteLine("Press enter to stop server");
      Console.ReadLine();
      server.Shutdown();
    }
  }

There are a few things more that can be done with HttpServer.

//mounting virtual path with a lambda (shown in previous example)
server.Mount("/virtual/path", (req, resp) => DoSomethingWith(req, resp));

//mounting virtual path to serve static files
server.Mount("/virtual/path", @"c:\some\directory");

//hiding a virtual path
server.Mount("/virtual/path/subdir", new ResourceNotFoundHandler());

As it is, HttpServer supports only GET requests. The plan is to add more support (for features that make sense in a unit testing scenario) with time.

I obviously don't envision Juicy becoming a full-fledged web server that I can recommend using in a live web site. But I can see it being helpful in the scenarios I've just described and for testing in general.

I'm sold. Where can I get it?

This project is hosted at GitHub: http://github.com/sergiopereira/juicy/tree/master, where you can download the source directly or even clone the repository :

c:\projects>git clone git://github.com/sergiopereira/juicy.git