Saturday, April 18, 2015

Finish the REST (Part 2) with Fiddler debugging and testing

We are doing three things for this part: (1) finish coding the REST api (2) Debug with Fiddler (3) Write Frisby test against our API.

Finishing the REST api is the easy part. Make a folder with the path api/v1/ inside the routes folder. Inside the api folder is another folder called v1. I do this just out of habit. APIs will change in even in a production environments. When that happens, I just add a v2 folder. It's just a cheap and easy way to future proof REST API endpoints.

After the folders, create a posts.js file inside.

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');

// Get the model
var post = mongoose.model('Post');

// GET /api/v1/posts - GET ALL
router.get('/', function (req, res) {
    post.find({}, function (err, posts) {
        res.json(posts);
    });
});

// GET /api/v1/posts/:post_id
router.get('/:post_id', function(req, res) {
    post.findById(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        res.json(post);
    });
});

// POST /api/v1/posts
router.post('/', function(req, res) {
    var newPost = new Post();
    newPost.title = req.body.title;
    newPost.body = req.body.body;
    newPost.author = req.body.author;
    newPost.published = req.body.published;

    newPost.save(function(err) {
        if (err) res.send(err);
        res.json({ message: 'Post created!' });
    });
});

// PUT /api/v1/posts
router.put('/', function(req, res) {
    post.findById(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        post.title = req.body.title;
        post.body = req.body.body;
        post.author = req.body.author;
        post.published = req.body.published;
        post.meta.favs = req.body.favs;
        post.meta.dvotes = req.body.dvotes;
        post.meta.uvotes = req.body.uvotes;

        post.save(function(err) {
            if (err) res.send(err);

            res.json({ message: 'Post updated' });
        });
    });
});

// DELETE /api/v1/posts/:post_id
router.delete('/:post_id', function(req, res) { 
    post.findByIdAndRemove(req.params.post_id, function(err, post) {
        if (err) res.send(err);

        res.json({ message: 'Post deleted!' });
    });
});

module.exports = router;

The whole thing should be fairly easy to figure out since this is the actual CRUD stuff.

Run the project and we should see our web page. Now we move to Fiddler to see around our API. Remember, you can just Postman instead of fiddler.

Start here: The Composer Tab in Fiddler
After you've open Fiddler, just go to the composer tab and add the API url you're interested in. Don't forget the HTTP verb. Press the Execute button on the top right to see the results.

You'll be able to go to the other tabs to see a lot of information.

The Inspectors tab contents is what we are interested in. This is where we see what's inside the reply from our API (or lack thereof if that is what we are expecting).

And finally, tests for our REST API endpoints. I wanted to add tests for our API to ensure behavior and for regression. It just makes sure I don't break the API as we continue working on this little project of ours.

We will be using the Frisby framework. Frisby is made to test REST API on node.js projects.

So, we install Frisby. Open a terminal, navigate to the project folder and type in:

npm install -g --save frisby

That should install the latest frisby version and save it a dependency in our package.json file. When frisby installed, create a folder named spec and inside that another folder named api. Inside these folders, a javascript file named posts_spec.js.

var frisby = require('frisby');
var baseURL = 'http://localhost:1337/'; // just replace if on live server

frisby.create('Status 200 for GET /api/v1/posts is returned')
    .get(baseURL + 'api/v1/posts')
    .expectStatus(200)
    .toss();

frisby.create('Status 200 for GET /api/v1/posts/:id')
    .get(baseURL + 'api/v1/posts/5525f1e3f6a7f3a00b234a09')
    .expectStatus(200)
    .expectJSON({ 'author': 'jaypax' })
    .toss();


Here we have two tests. Feel free to add more.

Now we just need to run it for which we need jasmine-node.

npm install -g --save jasmine-node

After NPM is done, you should be able to run the command in your terminal: jasmine-code spec/api/


Friby results after running the test 
By the way, you need the project to be running in order to run the test.

You basically have two terminals open: 1 terminal running the project and other terminal to run the test from.

Clone the code at the github repo.

Wednesday, April 15, 2015

Coding the REST services (Part 1) - The model

Coding up the REST services part is similar to coding up the CRUD parts for you traditional desktop application. The difference is quite subtle because you'll be also dealing with HTTP verbs - POST, GET, PUT, DELETE. We are going to make the data model first so we have something to interact with.

First step is creating a connection. In our case, we are connecting to MongoLab, so in your app.js file you add the following:

// our libs
var mongoose = require('mongoose');
var uriUtil = require('mongodb-uri');

// our connection function
var connectToMongoLab = function () {
    var username = process.env.MongolabUsername;     // external var for our username
    var password = process.env.MongoLabPassword;     // same for the password

    var mongolabUri = "mongodb://" + username + ":" + password + "@ds035448.mongolab.com:35448/dbhaxspace";
    var mongooseUri = uriUtil.formatMongoose(mongolabUri);
    var options = {
        server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
        replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
    };
    mongoose.connect(mongooseUri, options);  // connect us to the db with these options
};

connectToMongoLab(); 

mongoose.connection.on('error', console.log);   // if error in connecting to db, dump errmsg to console
mongoose.connection.on('disconnected', connectToMongoLab); // if disconnected just reconnect

// load models
fs.readdirSync(__dirname + "/models").forEach(function(file) {
    if (~file.indexOf('.js')) require(__dirname + '/models/' + file);
});

This should be added before the routes portions. Now for the actual model.

We're using Mongoose to model our data. Think Entity Framework if you're a C# guy, Hibernate (or JPA) if Java and SQLAlchemy for the python guys. (No, PHP gets not love. #Dealwithit)

Create a folder called Model and create a new javascript file in that folder. In our project, our model is called post and it's declared in the post.js file.

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var PostSchema = new Schema({
    title: { type: String, default: '' },
    author: { type: String, default: '' },
    body: String,
    published: Boolean,
    date: { type: Date, default: Date.now },
    geoloc: {
        latitude: { type: Number, default: 0 },
        longitude: { type: Number, default: 0 },
        label: { type: String, default: ''} 
    },
    meta: {
        uvotes: { type: Number, default: 0 },
        dvotes: { type: Number, default: 0 },
        favs: { type: Number, default: 0 }
    }
});
// methods
PostSchema.method({
    findAll : function(cb) {
        return this.model('Post').find({}, cb);
    }  
});
// statics
PostSchema.static({

});
// register
mongoose.model('Post', PostSchema, 'posts');

Mongoose schema's have some pretty nifty features like types, methods and statics that can be part of the model. The whole thing then wraps up when you call the mongoose.model() function to register the model.

Once we have our model registered. We can then call our model into any part of the app.

var mongoose = require('mongoose');
// Get the model
var post = mongoose.model('Post');

We will pick this up on part 2 where I actually show you the REST parts.

Thursday, April 9, 2015

Node is up: hello world

This "Hello world" thing has a long history in programming but very few student programmers really understood it purpose or assumed wrongly what it's purpose.

The "hello world" program is the first thing done on learning new programming languages and it's also the first program done when trying out a newly setup environment to make sure everything is working. This is what we are doing now.
  1. Start by creating our "Basic Node.js Express 4 Application" in Visual Studio.


  2. Run it, point your browser to http://localhost:1337/ and see our web app running. If it runs we are golden and continue to the next set of steps. If not, then you better get to fixing.

  3. Now that we have a known working node.js app. We should commit this to a source repo like github or bitbucket. At the start of this tutorial I did mention I'll be using SourceTree to manage this but you can go old school and use a terminal if you feel that SourceTree is creepy.



    So create a new repository and don't commit any files yet.

  4. We have to create a .gitignore file so we don't commit temporary or intermediate files. We will be using this .gitignore file. So just go to the root of the new repo and copy that .gitignore file there. SourceTree should be able to pick it the new file and use it, "ignoring" files listed in the gitignore..

    Don't forget to commit the files and push it into your repo. Read this if you need more details about pushing into a remote repo.
Now for the lazy, you can instead clone the repo here. Or if you're just lost then follow this tutorial on how to use git.

Don't be afraid to play around with the code. If you screw up, just delete the offending project folder and clone the project again. After cloning, you'll be good again.