In this lab we will be using our WebStorm IDE to build a simple Node/Express Server to initially act as a Web Service APi for a related Android Mobile App, and eventually it will be our back-end to a full MEAN Stack Web App.
In this Lab, you will be required to build the first version of our Donation Case Study Web App, called DonationWeb 1.0. We will scaffold the app similar to Lab 1, so if you're still a bit unsure of this process, maybe have a go at it again?
On completion of this lab you'll be able to
In this version we will be implementing a simple RESTful APi with the following routes
We're going to build our first Node/Express DonationWeb project, so (assuming you already have it installed) launch your WebStorm IDE and create a new Node/Express Project as follows;
Select 'Create New Project' and you should get something like this:
Select a 'Node.js Express App'
and browse to the location you want to store your project files. It's probably a good idea to store all your web apps in a single folder (ssd4 for me here) and create a new folder for our specific web app donationweb-1.0 (as below).
and make sue you choose EJS again as the templating option (like before)
Your project should now look like this
Once again, click on the 'play' button to run/launch your Web App..
if you've followed all the steps correctly you should be able to run your app (or visit http://localhost:3000) and see the following
Now, if you'd rather your browser launch automatically you can configure you 'Run' options and choose the Browser you prefer
Just be sure to 'tick' the 'After Launch' check box
Close the browser tab/window and run your app again, to confirm your new run configuration is correct.
The next few steps will involve implementing some of our RESTful APi and some WebStorm configuration changes.
Before we can think about accessing data on our Server via a RESTful APi, we first need the actual data :) , so this step will involve creating a list of 'Donations' that we can 'expose' via our APi.
The first thing we need to do is create a new directory in our root directory called models/
and within that directory create a new file called donations.js.
Now, paste the following code into your newly created .js file
var donations = [
{id: 1000000, paymenttype: 'PayPal', amount: 1600, upvotes: 1},
{id: 1000001, paymenttype: 'Direct', amount: 1100, upvotes: 2}
];
module.exports = donations;
Notice the field (id) in our model, this will be useful later on for deleting etc.
Your project should now look something like this
With our "backend" model in place, it's now time to open some routes that a client can interact with. The following are a list of actions a user can perform:
The actions map directly to several routes, which are described as follows:
Before we proceed, WebStorm has a very nice (and useful!) feature to assist the developer in writing javascript - Code Assistance, which happens to disabled by default, so we need to turn it on, as follows;
File->Default Settings
Languages & Frameworks->Node.js & NPM
Enable Node.js Core Library
To keep things organised we will be defining these routes in a routes/donations.js file, so create a new file 'donations.js' in the existing 'routes' folder in your project.
Let's begin by opening up the first route we listed, which should return a JSON list containing all donations. We start by creating a function (findAll) for retrieving donations in our routes/donations.js file.
var donations = require('../models/donations');
var express = require('express');
var router = express.Router();
router.findAll = function(req, res) {
// Return a JSON representation of our list
res.json(donations);
}
module.exports = router;
We make sure we import express and have a handle to our donations model. By right, we should have some error handling in there, but we'll be optimistic!
Next, inside our app.js we need to define the actual route which will trigger the above function so add this around line 26/27 (there'll be another, similar, route around that line so just add it after it)
app.get('/donations', donations.findAll);
to add the actual GET APi route.
Now, try and run your app and see what happens....
You probably got something like this
We're trying to call a function 'findAll' on an object (donations) that the js interpreter can't find.
Ordinarily, we'd have to manually add in the javascript we need, but we can get WebStorm to do this for us - highlight the error and hit Alt+Enter (on a Mac) and you get the following;
Choose the first 'fix' and the necessary 'requires' statement is added to our js file - kinda handy don't you think?!
Now, to actually test our APi we need to launch our Server again and point the browser at http://localhost:3000/donations and we should get back a json string of our data, like so.
Over time, this would probably become a bit time consuming, but WebStorm to the rescue again :) there's a feature to Test RESTful Web Service, so launch that like so
and you get the REST Client window, so select/type in the following for out test request
On the 'Request' tab, update the 'Accept' Header application/json
and 'play' the request
If everything goes according to plan, you'll see the same json list of donations in the Response.
You could continue to use the browser to test the APi, but things will get a bit tricky when we want to test our add & update requests so we'll stick with the REST Client for the moment.
Our first route returned all the donations to a client, but what if the client only want's to get at a single donation - that's what our next route 'findOne' will do.
Here's the function (findOne) to be added to our routes/donations.js file
router.findOne = function(req, res) {
var donation = getByValue(donations,req.params.id);
if(donation != null)
res.json(donation);
else
res.json({ message: 'Donation NOT Found!'});
}
and our route for app.js
app.get('/donations/:id', donations.findOne);
You've probably noticed (or maybe you didn't!) that there's a 'helper' function (getByValue) we need to write for our 'findOne' function to work properly.
Here's the function stub, so see can you work out how to find the donation object in arr with id id and return it.
function getByValue(arr, id) {
// put your code solution here
}
Now that we have another GET 'service' in our RESTful APi, we should really test it via our REST Client.
GETing donation with id '1000001'
/donations/1000001
requesting donation with id '10000011'
/donations/10000011
We will eventually be using our previously developed Android App to make client requests on a deployed version of our MEAN Web App but for now you can actually run your server locally and connect with your Android App as follows;
run ipconfig (windows) or ifconfig (mac) to get your machines IP address.
Initially Launch of App (Total is $2700, from Node Web APi)
List all our Donations in the Report
Upvote a Donation (using the WebStorm REST Client) and Refresh Report
Before we go any further, here's the missing code from the previous step:
function getByValue(arr, id) {
var result = arr.filter(function(o){return o.id == id;} );
return result ? result[0] : null; // or undefined
}
Recall our routes, described as follows:
We've already implemented the first two, so now let's have a go at
Similar to the previous step, we start by creating a function (addDonation) for adding a single donation in our routes/donations.js file
router.addDonation = function(req, res) {
//Add a new donation to our list
var id = Math.floor((Math.random() * 1000000) + 1); //Randomly generate an id
// parameters to store
// id (for id)
// req.body.paymenttype (for paymenttype)
// req.body.amount (for amount)
// 0 (for upvotes)
var currentSize = donations.length;
donations.push(/*add the relevant code here*/);
if((currentSize + 1) == donations.length)
res.json({ message: 'Donation Added!'});
else
res.json({ message: 'Donation NOT Added!'});
}
Notice we only return a json message confirming (or Not) we've added the donation.
Next, inside our app.js we need to define the actual route which will trigger the above function so keeping in mind the route is /donations with a POST request, see can you make the necessary additions?
Now that we have a POST 'service' in our RESTful APi, let's test it via our REST Client.
We need to fill in the Request Body for our POST
POSTing donation data in JSON format
{"id":0,"paymenttype":"Direct","amount":500,"upvotes":0}
GET all donations again to confirm
Here's what we need to implement the 'Upvote' route
routes/donations.js
router.incrementUpvotes = function(req, res) {
//Add 1 to upvotes property of the selected donation based on its id
var donation = getByValue(donations,req.params.id);
donation.upvotes += 1;
}
app.js
app.put('/donations/:id/votes', donations.incrementUpvotes);
Now that we have a PUT 'service' in our RESTful APi, let's test it via our REST Client.
UPDATEing donation votes with id '941345'
/donations/941345/votes
Again, we start with the function in our routes/donations.js file
router.deleteDonation = function(req, res) {
//Delete the selected donation based on its id
var donation = getByValue(donations,req.params.id);
var index = donations.indexOf(donation);
var currentSize = donations.length;
donations.splice(index, 1);
if((currentSize - 1) == donations.length)
res.json({ message: 'Donation Deleted!'});
else
res.json({ message: 'Donation NOT Deleted!'});
}
and update our app.js accordingly
app.delete('/donations/:id', donations.deleteDonation);
Notice we are using our own 'lookup' function to find a particular donation but be sure you understand how it works....
Now that we have a DELETE 'service' in our RESTful APi, let's test it via our REST Client.
DELETEing donation with id '1000001'
/donations/1000001
A quick GET all to confirm
You can find the solution to this lab here and your project should look something like this