diff --git a/.gitignore b/.gitignore
index a4964b7d85653500bd8d78d3e822e9c2053eee0e..e1b45dc5c40ab9197e66a0cbbfdd7ef71a4ae887 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 *.log
 *.out
 *.pid
+*.js
+*.js.map
 /.trash
 /pids
 /logs
@@ -10,3 +12,4 @@
 /config/*.yaml
 /doc/build
 /coverage
+/typings
diff --git a/package.json b/package.json
index 87749f103ccbd79144687ffb214de8be9c802a1e..7fd92ed711301d2a7b0b2ac03193fe6a5adda91b 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,10 @@
   "description": "BlenDB",
   "main": "index.js",
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "prestart": "tsc",
+    "start": "node build/src/boot",
+    "pretest": "tsc",
+    "test": "mocha"
   },
   "repository": {
     "type": "git",
@@ -31,7 +34,9 @@
     "jshint": "^2.9.2",
     "mongodb": "^2.2.5",
     "osprey": "^0.3.2",
-    "raml2html": "^2.4.0"
+    "raml2html": "^2.4.0",
+    "typescript": "^1.8.10",
+    "typings": "^1.3.2"
   },
   "devDependencies": {
     "chai": "^3.5.0",
diff --git a/src/core/mongo.js b/src/api/controllers/collect.ts
similarity index 66%
rename from src/core/mongo.js
rename to src/api/controllers/collect.ts
index f6f4dccd44872a32870e6de3790cace342634976..76b3e3bd9ff18bbe9ccacbafb423558262c9386e 100644
--- a/src/core/mongo.js
+++ b/src/api/controllers/collect.ts
@@ -18,25 +18,17 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
+import * as express from "express";
 
-const MongoClient = require('mongodb').MongoClient;
+export class CollectCtrl {
+    static write(req: express.Request, res: express.Response, next: express.NextFunction) {
+        if ('_id' in req.body) {
+            res.status(400)
+                .json({ message: 'Property named \'_id\' is protected.' });
+            return;
+        }
 
-class Mongo {
-    constructor() {
-        this.db = undefined;
-    }
-
-    connect(connectionString) {
-        MongoClient.connect(connectionString, (err, db) => {
-            if (err) {
-                console.error(err);
-                return;
-            }
-
-            this.db = db;
-        });
+        res.status(500)
+            .json({ message: 'Error while writing to the database.' });
     }
 }
-
-module.exports = new Mongo();
diff --git a/src/api/controllers/data.js b/src/api/controllers/data.js
deleted file mode 100644
index 8edbaa99b6d35c4ed4ae06b98788c8af118e4fb2..0000000000000000000000000000000000000000
--- a/src/api/controllers/data.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
- * Departamento de Informatica - Universidade Federal do Parana
- *
- * This file is part of blendb.
- *
- * blendb is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * blendb is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-'use strict';
-
-const aggregator = require('core/aggregator');
-
-class Data {
-    read(req, res, next) {
-        let metrics = req.query.metrics.split(',');
-        let dimensions = req.query.dimensions.split(',');
-
-        aggregator.query(metrics, dimensions, (err, data) => {
-            if (err) {
-                console.error(err);
-                res.status(500).json({ message: 'Query execution failed ' +
-                    'because of an unknown error.' });
-                return;
-            }
-
-            res.json({ data });
-        });
-    }
-}
-
-module.exports = new Data();
diff --git a/src/api/controllers/data.ts b/src/api/controllers/data.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3497c5b5981f65ac5ee93b113359df4b2107d625
--- /dev/null
+++ b/src/api/controllers/data.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
+ * Departamento de Informatica - Universidade Federal do Parana
+ *
+ * This file is part of blendb.
+ *
+ * blendb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * blendb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import * as express from "express";
+
+export class DataCtrl {
+    static read(req: express.Request, res: express.Response, next: express.NextFunction) {
+        let metrics = req.query.metrics.split(',');
+        let dimensions = req.query.dimensions.split(',');
+
+        res.status(500).json({ message: 'Query execution failed ' +
+            'because of an unknown error.' });
+    }
+}
diff --git a/src/api/router-v1.js b/src/api/router-v1.ts
similarity index 78%
rename from src/api/router-v1.js
rename to src/api/router-v1.ts
index 7a95b16b7d9ced0ce4f1b2c7f43af19111fc9509..d8c4211c02d1504559597b66f66bb23ff6c0511a 100644
--- a/src/api/router-v1.js
+++ b/src/api/router-v1.ts
@@ -18,15 +18,13 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
-
 const osprey = require('osprey');
 
 // import controllers
-const data = require('./controllers/data');
-const collect = require('./controllers/collect');
+import { DataCtrl } from './controllers/data';
+import { CollectCtrl } from './controllers/collect';
 
-const router = module.exports = osprey.Router();
+export const router = osprey.Router();
 
-router.get('/data', data.read);
-router.post('/collect/{class}', collect.write);
+router.get('/data', DataCtrl.read);
+router.post('/collect/{class}', CollectCtrl.write);
diff --git a/src/boot.ts b/src/boot.ts
new file mode 100755
index 0000000000000000000000000000000000000000..1eb4b57c8e8102c1740b638451d48367c1a9af5e
--- /dev/null
+++ b/src/boot.ts
@@ -0,0 +1,59 @@
+#!/usr/bin/env node
+/*
+ * Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre
+ * Departamento de Informatica - Universidade Federal do Parana
+ *
+ * This file is part of blendb.
+ *
+ * blendb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * blendb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// external libraries
+import express = require('express');
+import path = require('path');
+
+const osprey = require('osprey');
+const ramlParser = require('raml-parser');
+
+// create a new express app
+const app = module.exports = express();
+
+// load router
+import { router } from './api/router-v1';
+
+// parse the RAML spec and load osprey middleware
+ramlParser.loadFile('specs/blendb-api-v1.raml')
+    .then((raml: any) => {
+        app.use('/v1',
+            osprey.security(raml),
+            osprey.server(raml),
+            router);
+
+        if (!module.parent) {
+            let port = process.env.PORT || 3000;
+            app.listen(port);
+
+            if (app.get('env') === 'development') {
+                console.log('Server listening on port ' + port + '.');
+            }
+        }
+        else {
+            // signalize to the test suite that the server is ready to be tested
+            app.locals.ready = true;
+        }
+    },
+    (err: any) => {
+        console.error('RAML Parsing Error: ' + err.message);
+        process.exit(1);
+    });
diff --git a/src/api/controllers/collect.js b/src/core/aggregate.spec.ts
similarity index 54%
rename from src/api/controllers/collect.js
rename to src/core/aggregate.spec.ts
index 518bf502570c334dc6524c70475d8df76bd69e0a..5db3d9a2861d2df3443c9458e0eb8f1850c2d038 100644
--- a/src/api/controllers/collect.js
+++ b/src/core/aggregate.spec.ts
@@ -18,30 +18,23 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
+import { expect } from 'chai';
 
-const mongo = require('core/mongo');
+import { Aggregate } from './aggregate';
 
-class Collect {
-    write(req, res, next) {
-        let collection = mongo.db.collection('raw.' + req.params.class);
+describe('aggregate class', () => {
+    it('should be instantiated with an array metrics and one of dimensions', () => {
+        let aggr = new Aggregate(['met:one'], ['dim:one', 'dim:two']);
+        expect(aggr).to.be.an('object');
+    });
 
-        if ('_id' in req.body) {
-            res.status(400)
-                .json({ message: 'Property named \'_id\' is protected.' });
-            return;
-        }
+    it('should not be instantiated with an empty array of metrics', () => {
+        let aggr = new Aggregate([], ['dim:one', 'dim:two']);
+        expect(aggr).to.be.an('object');
+    });
 
-        collection.insertOne(req.body, function (err, r) {
-            if (err) {
-                res.status(500)
-                    .json({ message: 'Error while writing to the database.' });
-                return;
-            }
-
-            res.status(200).json({ _id: r.insertedId });
-        });
-    }
-}
-
-module.exports = new Collect();
+    it('should not be instantiated with an empty array of dimensions', () => {
+        let aggr = new Aggregate(['met:one'], []);
+        expect(aggr).to.be.an('object');
+    });
+});
diff --git a/src/core/aggregate.js b/src/core/aggregate.ts
similarity index 84%
rename from src/core/aggregate.js
rename to src/core/aggregate.ts
index aece430c41bc67c6ff4a7092b40144bbd0ffa507..aa46fd8e598d764f103757d11efc5c4d33a64ce3 100644
--- a/src/core/aggregate.js
+++ b/src/core/aggregate.ts
@@ -18,17 +18,19 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
+export class Aggregate {
+    metrics: string[];
+    dimensions: string[];
+    data: any[];
 
-class Aggregate {
-    constructor(metrics, dimensions, options) {
+    constructor(metrics: string[], dimensions: string[], options?: any) {
         this.metrics = metrics;
         this.dimensions = dimensions;
 
         this.data = [];
     }
 
-    push(data) {
+    push(data: any) {
         this.data.push(data);
     }
 
@@ -36,5 +38,3 @@ class Aggregate {
         this.data = [];
     }
 }
-
-module.exports = Aggregate;
diff --git a/src/blendb.js b/src/core/server.ts
similarity index 78%
rename from src/blendb.js
rename to src/core/server.ts
index d1968a761a91f2f7bda2223104105cc2d8a77123..097d10008545795030d809076dd8801d8b1edbd1 100644
--- a/src/blendb.js
+++ b/src/core/server.ts
@@ -20,20 +20,24 @@
 
 'use strict';
 
-const hash = require('util/hash');
+import { Hash } from '../util/hash';
 
-const Source = require('core/source');
-const Transformer = require('core/transformer');
-const Aggregate = require('core/aggregate');
+import { Source } from './source';
+import { Transformer } from './transformer';
+import { Aggregate } from './aggregate';
+
+export class Server {
+    sources: Map<string,Source>;
+    transformers: Map<string,Transformer>;
+    aggregates: Map<string,Aggregate>;
 
-class BlenDB {
     constructor() {
         this.sources = new Map();
         this.transformers = new Map();
         this.aggregates = new Map();
     }
 
-    source(name, options) {
+    source(name: string, options?: any) {
         if (this.sources.has(name)) {
             return this.sources.get(name);
         }
@@ -44,7 +48,7 @@ class BlenDB {
         }
     }
 
-    transformer(name, options) {
+    transformer(name: string, options?: any) {
         if (this.transformers.has(name)) {
             return this.transformers.get(name);
         }
@@ -55,11 +59,8 @@ class BlenDB {
         }
     }
 
-    aggregate(metrics, dimensions, options) {
-        metrics = Array.from(metrics);
-        dimensions = Array.from(dimensions);
-
-        const id = hash.sha1(metrics.sort() + dimensions.sort());
+    aggregate(metrics: string[], dimensions: string[], options?: any) {
+        const id = Hash.sha1(metrics.sort(), dimensions.sort());
 
         if (this.aggregates.has(id)) {
             return this.aggregates.get(id);
@@ -72,12 +73,12 @@ class BlenDB {
     }
 
     process() {
-        this.transformers.forEach((transformer) => {
+        this.transformers.forEach((transformer: Transformer) => {
             const source = this.source(transformer.source);
             const aggr = this.aggregate(transformer.metrics,
                 transformer.dimensions);
 
-            source.forEach((doc) => {
+            source.forEach((doc: any) => {
                 aggr.push({
                     metrics: transformer.extractMetrics(doc),
                     dimensions: transformer.extractDimensions(doc)
@@ -93,5 +94,3 @@ class BlenDB {
         console.log(this.aggregates);
     }
 }
-
-module.exports = { BlenDB, Source, Transformer };
diff --git a/src/core/source.js b/src/core/source.ts
similarity index 77%
rename from src/core/source.js
rename to src/core/source.ts
index 07ec973568fadec1ef9df03ab2a22b9b4db50404..38c8833de18f16226c7c13a327b1b3958cf7b953 100644
--- a/src/core/source.js
+++ b/src/core/source.ts
@@ -20,20 +20,23 @@
 
 'use strict';
 
-class Source {
-    constructor(name, options) {
+export class Source {
+    name: string;
+    data: any[];
+
+    constructor(name: string, options: any) {
         this.name = name;
 
         this.data = [];
     }
 
-    push(doc) {
+    push(doc: any) {
         this.data.push(doc);
     }
 
-    forEach(callback) {
-        this.data.forEach(callback);
+    forEach(callback: Function) {
+        this.data.forEach((value: any, index: number, array: any[]) => {
+            callback(value);
+        });
     }
 }
-
-module.exports = Source;
diff --git a/src/core/transformer.js b/src/core/transformer.ts
similarity index 74%
rename from src/core/transformer.js
rename to src/core/transformer.ts
index c8e27a257777a48494a2533d65b251d205569163..fab5549dd79a8af65676a84b91312bb6ca656d4b 100644
--- a/src/core/transformer.js
+++ b/src/core/transformer.ts
@@ -20,24 +20,27 @@
 
 'use strict';
 
-class Transformer {
-    constructor(name, options) {
+export class Transformer {
+    source: string;
+    metrics: string[];
+    dimensions: string[];
+    extractors: any;
+
+    constructor(name: string, options: any) {
         this.source = options.source || null;
         this.metrics = options.metrics || [];
         this.dimensions = options.dimensions || [];
         this.extractors = {
-            metrics: options.extractors.metrics || ((doc) => null),
-            dimensions: options.extractors.dimensions || ((doc) => null)
+            metrics: options.extractors.metrics || ((doc: any): any => null),
+            dimensions: options.extractors.dimensions || ((doc: any): any => null)
         };
     }
 
-    extractMetrics(doc) {
+    extractMetrics(doc: any) {
         return this.extractors.metrics(doc);
     }
 
-    extractDimensions(doc) {
+    extractDimensions(doc: any) {
         return this.extractors.dimensions(doc);
     }
 }
-
-module.exports = Transformer;
diff --git a/test/util/hash.spec.js b/src/util/hash.spec.ts
similarity index 72%
rename from test/util/hash.spec.js
rename to src/util/hash.spec.ts
index 2de7ca6e2187a77a07bb68ab91597c006cb8ee8d..0aa910736b9ef869b7ddd29d10c7ecdd293d1300 100644
--- a/test/util/hash.spec.js
+++ b/src/util/hash.spec.ts
@@ -18,26 +18,21 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
+import { expect } from 'chai';
 
-/* globals expect */
-/* jshint -W024 */
-/* jshint expr:true, maxlen:false */
-/* jscs:disable maximumLineLength */
-
-const hash = require('util/hash');
+import { Hash } from './hash';
 
 describe('hash utility library', () => {
     it('should generate a sha1 hash for a collection of objects', () => {
-        let h = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
 
         expect(h).to.be.a('string');
         expect(h).to.not.be.empty;
     });
 
     it('should generate the same hash for the same input', () => {
-        let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
-        let h2 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h2 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
 
         expect(h1).to.be.a('string');
         expect(h2).to.be.a('string');
@@ -45,8 +40,8 @@ describe('hash utility library', () => {
     });
 
     it('should generate the same hash for different order of input', () => {
-        let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
-        let h2 = hash.sha1('test', ['list', 'of', 'things'], { obj: 'test' });
+        let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h2 = Hash.sha1('test', ['list', 'of', 'things'], { obj: 'test' });
 
         expect(h1).to.be.a('string');
         expect(h2).to.be.a('string');
@@ -54,8 +49,8 @@ describe('hash utility library', () => {
     });
 
     it('should not generate the same hash for distinct input', () => {
-        let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
-        let h2 = hash.sha1('test', { obj: 'test', x: true },
+        let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h2 = Hash.sha1('test', { obj: 'test', x: true },
             ['list', 'of', 'things']);
 
         expect(h1).to.be.a('string');
@@ -64,8 +59,8 @@ describe('hash utility library', () => {
     });
 
     it('should not generate the same hash for different order in deep lists', () => {
-        let h1 = hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
-        let h2 = hash.sha1('test', { obj: 'test' }, ['of', 'list', 'things']);
+        let h1 = Hash.sha1('test', { obj: 'test' }, ['list', 'of', 'things']);
+        let h2 = Hash.sha1('test', { obj: 'test' }, ['of', 'list', 'things']);
 
         expect(h1).to.be.a('string');
         expect(h2).to.be.a('string');
diff --git a/src/util/hash.js b/src/util/hash.ts
similarity index 93%
rename from src/util/hash.js
rename to src/util/hash.ts
index 9a7501f66f812ab18b2075ade47cac16218fc6d6..f89379f0f14629ad2ca5e0e7bf824242533f1a63 100644
--- a/src/util/hash.js
+++ b/src/util/hash.ts
@@ -20,10 +20,10 @@
 
 'use strict';
 
-const crypto = require('crypto');
+import crypto = require('crypto');
 
-class Hash {
-    sha1(...objects) {
+export class Hash {
+    static sha1(...objects: any[]): string {
         let hash = crypto.createHash('sha1');
 
         objects
@@ -46,5 +46,3 @@ class Hash {
         return hash.digest('hex');
     }
 }
-
-module.exports = new Hash();
diff --git a/test/global.js b/test/global.ts
similarity index 76%
rename from test/global.js
rename to test/global.ts
index b3bc09cac34de9bb936e4c9c1eaf891549114fe6..557810b6f373c18e3b808d46d48da77fb8cad3f7 100644
--- a/test/global.js
+++ b/test/global.ts
@@ -18,12 +18,4 @@
  * along with blendb.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-'use strict';
-
 process.env.NODE_ENV = 'test';
-
-global.expect = require('chai').expect;
-
-// Add the ./src directory to require's search path to facilitate import
-// modules later on (avoiding the require('../../../../module') problem).
-require('app-module-path').addPath(__dirname + '/../src');
diff --git a/test/mocha.opts b/test/mocha.opts
index 150fdfab63872536b78cb253d8be6af0c4a66fee..701d3701b30095eeb86e1bb2d12120a777b6b4d3 100644
--- a/test/mocha.opts
+++ b/test/mocha.opts
@@ -1,4 +1,4 @@
---require ./test/global.js
+--require ./build/test/global.js
 --reporter spec
 --ui bdd
 --recursive
@@ -7,3 +7,4 @@
 --slow 300
 --check-leaks
 --globals expect
+./build/**/*.spec.js
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..00e2014e5a9dc88fe25778da3f6a91f423c8f940
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "pretty": true,
+    "target": "es5",
+    "module": "commonjs",
+    "outDir": "./build",
+    "noImplicitAny": true,
+    "removeComments": true,
+    "preserveConstEnums": true,
+    "sourceMap": true
+  },
+  "exclude": [
+      "node_modules"
+  ],
+  "compileOnSave": false
+}
diff --git a/typings.json b/typings.json
new file mode 100644
index 0000000000000000000000000000000000000000..82bbd7cac0a64e7e8a7572c7dc5f8aeefc423b3f
--- /dev/null
+++ b/typings.json
@@ -0,0 +1,11 @@
+{
+  "globalDependencies": {
+    "chai": "registry:dt/chai#3.4.0+20160601211834",
+    "express": "registry:dt/express#4.0.0+20160708185218",
+    "express-serve-static-core": "registry:dt/express-serve-static-core#4.0.0+20160817171221",
+    "mime": "registry:dt/mime#0.0.0+20160316155526",
+    "mocha": "registry:env/mocha#2.2.5+20160723033700",
+    "node": "registry:env/node#6.0.0+20160813135048",
+    "serve-static": "registry:dt/serve-static#0.0.0+20160606155157"
+  }
+}