ExpressJS with TypeScript


expressjs, typescript

ExpressJS with TypeScript


Daniel Shin - July 15, 2015

It’s been a while since I wrote the last post.

This post covers my recent venture into TypeScript, yet another Javascript transcompiling language.

My primal motivation for TypeScript was from my recent startup experience, Globl. It currently runs an API server built with Node.JS.

When I first started, I used CoffeeScript since its terse syntax allowed me to do a faster iteration. However, as the codebase gets bigger and API becomes more complex, I quickly found myself in the depth of never ending regression bugs.

These bugs were mostly stupid like function calls with wrong arguments and unmatching variables names etc. These kinds of bugs would have been easily solved with any statically typed language.

Long story short, I’ve delved into TypeScript and have never been happier. (No more Find All commands!)

However, this post won’t give an introduction to TypeScript as there are many good sources out there already, especially this handbook by Microsoft.

For any seasoned Javascript programmers with decent amount of statically typed language experience will have no problem learning the entirety of the language within a day or two.

Instead, I’d like to talk about this little code snippet that I wrote with Express.JS

export function GET<T extends typeof APIController>(path:string, paramsTypesInString: TypesArrayMap<string>) {
  return function<A>(target:T, methodString:string, descriptor:TypedPropertyDescriptor<A>) {
    app.get(path, (req: _ExpressRequest, res: _ExpressResponse) => {
      const [typesArrayMap, paramsMap] = extractParams(paramsTypesInString, req, MethodType.GET);

      if (target.handleInvalidParamTypes(typesArrayMap, res)) { return; }

      (<RequestHandlerWithParams> (<any> target)[methodString]).call(target, req, res, paramsMap);
    });
  }
}

This snippet utilizes the power of decorator in TypeScript (a.k.a Annotation in Java, Python …) For detailed discussion with decorator, refer to this and this.

It enables a new API Design Pattern for Express.JS like the following.

class UserController extends APIController {
  @GET("/user", { string: ["user_id"] })
  public static fetchUserData(req:_ExpressRequest, res:_ExpressResponse, params:ParamsType) {
    const {user_id} = params;
    
    res.send(user_id);
  }
}

There are several things to note here.

First, we take full advantage of the nice class inheritance provided by TypeScript. APIController is so-called abstract class, which has all the methods that are shared between its subclasses like handling client errors etc.

Second, we are using the decorator function that we’ve declared previously. First parameter to @GET is the path of this API method while the second parameter is the querystring that this API expects to receive.

Third, by using the decorator to associate API methods with paths, it enables us to write more declaratively. The typical API design by Express.JS usually involves association by imperative execution.

The end result looks quite similar to that of Ruby on Rails. By having its relevant data (path, querystring) close to the controller itself, it makes for both more readable and maintainable code since now there is no need for jumping back and forth between the API path declaration file and Controller.

Lastly, using decorator in TypeScript has no performance downside added since these decorators are executed at the design level, which means it executes declaratively once your server starts running not every time a new request comes.