Building web app using react.js, express.js, node.js and mongodb

ntroduction

For quite sometime now, I have been hearing some very interesting things about react.js like how fast it is and how cool it would be to pick react.js for your next web project. All that sounds very good but, unless we try it ourself, we won't be able to appreaciate it. So I decided to play with react.js for a while and see myself how accurate these claims are. Now there is just one problem, react.js documentation assumes certain level of experience with modern Javascript developement workflow, in short let's just say it's not very helpful if you are trying to use it for the first time. This series of articles is my attempt to put all the pieces together and show what it will take to build a fully functional react app.

In this series of articles, we will be creating a full stack single page JavaScript application from scratch. In Part 1 of this series we will focus completely on react.js workflow and create the front end piece of our app without any backend APIs or database. In the Part 2, we will create backend for our application using express.js and also persist our data in mongodb.

Prerequisites

In order to get the most out of this article I would suggest you to follow along. Some familiarity with node.js is required, but no prior knowledge of react.js or express.js is expected. You need to have node installed in your machine, everything else we will install as we progress.
So let's not waste any more time, open your favorite code editor and command shell, and jump right into code:

Project Setup

Like for all excellent node apps out there, story always begins with npm which is the package manage system for node.js platform. So quickly type following commands in your shell: 
npm install -g gulp bower nodemon
This command will install three very useful node utilities. Gulp is a task runner which we will use to make our like easier with some automation for mundane workflow tasks, Bower is a package manager for various front end libraries like bootstrap, jquery etc. this is just a nicer way of installing these libraries in your app as opposed to downloading them manually. We will also use "nodemon" to automatically restart our server application whenever a code change happens.
Next let's create a clean new directory and initialize it using following commands:
mkdir school-finder
npm init
bower init
I have named my directory "school-finder" and I ll keep referring to this as root directory throughout this article, "npm" and "bower" will prompt you for several questions, just keep hitting enter and they will be happy, at this point you will be having "package.json" and "bower.json" files in your root directory. Now let's install following node modules which we will be using:
npm install --save browserify reactify vinyl-source-stream gulp react react-dom express guid
If the above list seems too long and confusing then dont worry, we are using browserify so that we can use node like CommonJs module pattern to add references to various libraries as opposed to adding script tags in html pages. reactify is there to transpile JSX to javascript. JSX is xml like JavaScript syntax which react usage, you will understand exactly what I am saying once you have written some JSX code. You can find more information about these modules in npm website, for our intent and purposes let's assume these are needed.
Now create two more directories inside root directory, "app" and "server", inside "app" directory create "actions", "components","dist" and "stores" directories. Don't worry about the directory names too much, I will explain what each directory will contain once we reach there. Next add following two file ".bowerrc" and "gulpfile.js" in the root directory of your app, edit .bowerrc file and add following code inside:
{
    "directory":"app/lib"
}
Above code essentialy configures the directory where bower will install the libraries. One last thing we need to do is add reference to bootstrap library, we need to have some basic styling in our app to make it look good, so let's run following command:
bower install --save bootstrap-css
Well that seems a lot of work, even without writting a single line of react code we have so much in our project, but trust me it's worthwhile to do all this setup. Now let's start writting some code.

First line of code

Let's add a new file under "server" directory in the root foler name "server.js", which you might have guessed by now, is going to contain our applications backend. But wait! didn't we decide to focus on only the front end code here? Yes, we are still sticking to the same plan, we just need enough backend code to get us going. So let's add following code in the server.js file
var express = require("express");
var path = require("path");

var app = express();
app.use(express.static(path.join(__dirname,"../app/dist")));
app.listen(7777,function(){
    console.log("Started listening on port", 7777);
})
So above piece of code creates an express app which listens to http requests on port 7777. It also configures express to serve static content like html, css, images etc. from school-finder/app/dist directory. Next let's add "index.html" ,"style.css"and "main.jsx" files in "app" folder and edit index.html as shown below:
<!doctype html>
<html>

<head>
    <meta charset="UTF-8">
    <title>School Finder</title>
    <link href="bootstrap.min.css" rel="stylesheet" />
    <link href="style.css" rel="stylesheet" />
</head>

<body>
    <div class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">School Finder</a>
            </div>
        </div>
    </div>
    <div id="container" class="container"></div>
    <script src="main.js"></script>
</body>

</html>
Now launch your application using following command, and browse http://localhost:7777/index.html
nodemon .\server\server.js
at this point if your check developer tools of your browser, you will be getting 404 errors for few resources. Did you see that coming? Let's quickly fix that, edit gulpfile.js, which we had added previously, as shown below:

var gulp = require("gulp");
var browserify = require("browserify");
var reactify = require("reactify");
var source = require("vinyl-source-stream");

gulp.task("bundle", function () {
    return browserify({
        entries: "./app/main.jsx",
        debug: true
    }).transform(reactify)
        .bundle()
        .pipe(source("main.js"))
        .pipe(gulp.dest("app/dist"))
});

gulp.task("copy", ["bundle"], function () {
    return gulp.src(["app/index.html","app/lib/bootstrap-css/css/bootstrap.min.css","app/style.css"])
        .pipe(gulp.dest("app/dist"));
});

gulp.task("default",["copy"],function(){
   console.log("Gulp completed..."); 
});
In our gulpfile we have created two tasks,

a) Task bundle, takes "main.jsx" file, which is currently empty, transpils jsx code to plain javascript using "reactify" then stream sources it using "vinyl-source-stream" further creates "main.js" file on the fly in "dist" directory with transpiled js code in it.
b) Task copy,  takes index.html, bootstrap.min.css and style.css files files and copies them to "dist" folder.
now go to command shell and run "gulp" command, and then refresh the page in the browser. Check browsers developer tool and if everything went correct this far, you should not see any 404 errors.

Hello from react

I know you are getting impatient by now thinking so much work and not even a single line of react code, but remember we are trying to get a real world experience with react.js developement so keep moving. Let's add two empty files "SchoolInfo.jsx" and "SchoolsList.jsx" in "components" directory and edit them as shown below:
SchoolInfo.jsx
var React = require("react");

module.exports = React.createClass({
    render:function(){
        return(
            <div className="panel panel-default">
                <div className="panel-heading">
                    {this.props.info.name}
                </div>
                <div className="panel-body">
                    {this.props.info.tagline}
                </div>
            </div>
        )
    }
})
 SchoolsList.jsx
var React = require("react");
var SchoolInfo = require("./SchoolInfo.jsx")

module.exports = React.createClass({
   render:function(){
       return(
           <div className="row">
                <div className="col-md-6">
                    //We will add addSchool functionality here
                </div>
                <div className="col-md-6">
                    {
                        this.props.schools.map(function(s,index){
                            return(
                                <SchoolInfo info={s} key={"school"+index} />
                            )         
                        })
                    }
                </div>
           </div>
       )
   } 
});
There are few important points to highlight, 
a) We are able to use "require" constructs here in order to add references even though browsers do not support that construct, because we will not be adding these files references to our html files directly rather "browserify" library which we have configured as gulp task will resolve these dependencies and bundle all of them together in "main.js" file.
b) React applications are built using react coponents, you can think of components as self contained templates with functionality bundled within the template itself, although react purists will not agree with this definition, I am proposing it for the simplicity sake. We create a react component by using React.createClass method
c) The wierd looking syntax within the render function is called JSX, "reactify" which we have configured in the bundle task, trasnpiles this JSX code to JS code which browsers understand. You can write JavaScript expression within curly brackets "{}" which JSX transpiler interpolates while emitting JavaScript code.
d) Once you have created a react component, you can render that component inside another react component using familiar tag syntax, for example we have rendered SchoolInfo component inside SchoolList component using <SchoolInfo /> tag.
e) When you need to pass some data to a component, you can do so by  passing objects as value to components attributes while rendering it. Whatever you pass in component's attributes will be accessible within component in the form of a property of this.props Object. For example, while rendering SchoolInfo component in SchoolList, you pass school object in "info" attribute, which you can access in SchoolInfo component by this.props.info. 
Now open "main.jsx" file which is empty so far, and edit it as shown below:
var React = require("react");
var ReactDOM = require("react-dom");
var SchoolsList = require("./components/SchoolsList.jsx");

var _schools = [{name:"Lovedale",tagline:"this is a wonderful school"},
                {name:"Bishop",tagline:"Another great school"}];
                
function render(){
    ReactDOM.render(<SchoolsList schools={_schools} />, document.getElementById("container"));    
}
render();
Notice ReactDOM.render function, this indeed renders our react componet "SchoolsList" in Index.html file's div element with container id. The second parameter of ReactDOM.render function takes an html element which acts like a mount point for our entire react appAlso we are passing an array of school objects  as schools attribute ofSchoolList componentNow run the "gulp" command again from the command shell and refresh the page, and here you have a hello world react app.

React Flux Architecture

You must be thinking if we are going to build a whole application which is non trivial in nature with all these components, how far will I go? where will I place event handlers, all the REST API calls? How my application's architecture should look like? Well there is one answer to your all questions React Flux Architecture.

React flux is a programming patters for react applications which facebook usage internally. Flux ensures only unidirectional data flow throughout your application life cycle. Flux has following agents which keep the flux flow ticking:
1. Actions: these are the payloads with some data and some context (type) in short objects, these are created by some helper functions as a result of an activity in the view(mostly). For example when user clicks on an add button, we will create an action which will contain infomation to be added and the context. All actions are sent to the dispacher.
2. Dispatcher: dispatcher works like a global hub which triggers all the listeners rgistered to it whenever an action is sent to it.
3. Stores: stores register themselves with dispatchers, when dispatcher broadcasts an actions arrival, stores update themselves if that action is relavant to those stores, and emit a change event which causes UI to get updated.
4. Views: Views are the html rendered components.
Let's  implement the FLUX in our application and it will become a little more clear:

Creating a dispatcher

In your production apps you might choose to use a robust flux library but for this article let's create our own simple dispatcher so that we can see how exactly it works. So add a new file "dispatcher.js" in "app" directory and add the following code in it which is pretty much self explanatory:
var Guid = require("guid");

var listeners = {};

function dispatch(payload) {
    for (var id in listeners) {
        listeners[id](payload);
    }
}

function register(cb) {
    var id = Guid.create();
    listeners[id] = cb;
}

module.exports = {
    register: register,
    dispatch: dispatch
}
we are going to maintain all the registered listeners in the listeners object. Whoever is interested in registering itself to dispatcher can use register method, on the other side action helpers will call dispatch mehtod of dispatcher to broadcast an action.

Creating Actions Helper

Next let's add a new file "SchoolActions.js" in "actions" folder and add following code in it:
var dispatcher = require("../dispatcher");

module.exports = {
    addSchool:function(school){
        dispatcher.dispatch({
           school:school,
           type:"school:addSchool" 
        });
    },
    deleteSchool:function(school){
        dispatcher.dispatch({
           school:school,
           type:"school:deleteSchool" 
        });
    }
}
As you can see there are two actions in our Action helper, addSchool and deleteSchool . Both actions take information in the form of school object and then add a context to it in the form of type property which tells which action will be done on which item. Whenever an action method is called (that will be from a view), it will call dispatch method of dispatcher with the payload.

Creating Store

Now is the time to implement our store, so let's add "schoolsStore.js" file in "stores" directory and change it's code as shown below:
var dispatcher = require("../dispatcher");

function SchoolStore() {
    var listeners = [];
    var schools = [{ name: "Lovedale", tagline:"A wonderful school" }, 
                    { name: "Bishop",tagline:"An awesome school" }, 
                    { name: "Daffodils", tagline:"An excellent school" }];

    function getSchools() {
        return schools;
    }

    function onChange(listener) {
        listeners.push(listener);
    }

    function addSchool(school) {
        schools.push(school)
        triggerListeners();
    }

    function deleteSchool(school) {
        var _index;
        schools.map(function (s, index) {
            if (s.name === school.name) {
                _index = index;
            }
        });
        schools.splice(_index, 1);
        triggerListeners();
    }

    function triggerListeners() {
        listeners.forEach(function (listener) {
            listener(schools);
        });
    }

    dispatcher.register(function (payload) {
        var split = payload.type.split(":");
        if (split[0] === "school") {
            switch (split[1]) {
                case "addSchool":
                    addSchool(payload.school);
                    break;
                case "deleteSchool":
                    deleteSchool(payload.school);
                    break;
            }
        }
    });

    return {
        getSchools: getSchools,
        onChange: onChange
    }
}

module.exports = SchoolStore();
In our store implementation look at the dispatcher.register method call, this is where store registers itself with the dispatcher. When dispatcher broadcasts an action, store's registered callback is called where it checks the payload's type information and decides an appropriate action whether it's addSchool or deleteSchool in our case.

Also note that after taking appropriate action in response to dispatcher's call, store calls triggerListeners, this is the final piece of the puzzle which gives UI renderer an opportuinity to update the UI by calling all the subscribers of store's onChange event.
Now let's update "main.jsx" file so that it connects to the our store rather showing dummy data.
//main.jsx
var React = require("react");
var ReactDOM = require("react-dom");
var SchoolsList = require("./components/SchoolsList.jsx");
var schoolsStore = require("./stores/schoolsStore");
var _schools = schoolsStore.getSchools();
schoolsStore.onChange(function(schools){
    _schools = schools;
    render();
});

function render(){
    ReactDOM.render(<SchoolsList schools={_schools} />, document.getElementById("container"));    
}

render();
You can run the gulp again and after refreshing the page you will see new data appears on the screen. 

Addind behavior to components

Let's make our app a little more useful by adding add and delete functionality to it. We will create another react component, so let's add "AddSchool.jsx" file in "components" directory and add the following code in it:
var React = require("react");
var actions = require("../actions/SchoolActions");

module.exports = React.createClass({
    getInitialState:function(){
      return {
          name:"",
          tagline:""
      }  
    },
    addSchool:function(e){
        e.preventDefault();
        actions.addSchool(this.state);
    },
    handleInputChange:function(e){
      e.preventDefault();
      var name = e.target.name;
      var state = this.state;
      state[name] = e.target.value;
      this.setState(state);
    },
    render:function(){
        return(
            <form className="form" onSubmit={this.addSchool}>
                <div className="form-group">
                    <label className="control-label" htmlFor="name">School Name:</label>
                    <input type="text" className="form-control" id="name" name="name" value={this.state.name} onChange={this.handleInputChange} placeholder="School Name" />                    
                </div>
                <div className="form-group">
                    <label className="control-label" htmlFor="tagline">Tagline:</label>
                    <input type="text" className="form-control" id="tagline" name="tagline" value={this.state.address} onChange={this.handleInputChange} placeholder="Tagline" />                    
                </div>
                <div className="form-group">
                    <button className="btn" type="submit">Add School</button>
                </div>
            </form>
        )
    }
})
this component has some new syntax so let's quickly revisit.
1) We have added a form onSubmit handler "addSchool". You can add as many functions as you like within createClass parameter object.
2) Like we pass external data to a react components via attributes and we access this data by this.props object similar to that we can access internal state of our componet by this.state object. All react componets have their own internal state, and before we can use it, we need to initialize it by getInitialState function. This is a special function and the object it returns becomes the initial state of our components.
3) Like I have mentioned earlier, react does not support two-way-binding so we need to change the state ourself whenever we feel it's relevant, for example in our case whenever user enters some values in the form controls we update the state using handleInputChange function which get's triggered from onChange event handler. Notice we have used e.preventDefault() in event handlers to avoid page refresh.
4) When user clicks on "Add School" button, in the submit event handler we start the FLUX flow as shown in the following diagram:
 5) From Event handler we call action helper, which create an action and calls dispatcher. Dispatcher broadcasts the action and since store is subscribed to that action it updates itself and renders the UI. That is precisely the FLUX flow.
Now let's update the "SchoolsList.jsx" as shown below so that it renders the "AddSchool" component inside it:

var React = require("react");
var SchoolInfo = require("./SchoolInfo.jsx")
var AddSchool = require("./AddSchool.jsx");

module.exports = React.createClass({
   render:function(){
       return(
           <div className="row">
                <div className="col-md-6">
                    <AddSchool />
                </div>
                <div className="col-md-6">
                    {
                        this.props.schools.map(function(s,index){
                            return(
                                <SchoolInfo info={s} key={"school"+index} />
                            )         
                        })
                    }
                </div>
           </div>
       )
   } 
});
Also let's update the "SchoolInfo.jsx" to add delete functionality as shown below:
var React = require("react");
var actions = require("../actions/SchoolActions");

module.exports = React.createClass({
    deleteSchool: function(e){
        e.preventDefault();
        actions.deleteSchool(this.props.info);
    },
    render:function(){
        return(
            <div className="panel panel-default">
                <div className="panel-heading">
                    {this.props.info.name}
                    <span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>&times;</span>
                </div>
                <div className="panel-body">{this.props.info.tagline}</div>
            </div>
        )
    }
})
Now run the gulp command again and refresh the page, and we have a fully functional react app running. Try adding/deleting school and it should work fine.
So now we have finished our app's front end portion, however our app has a problem, if you refresh the page, all the new schools you added or deleted, disappear. This is because we are not persisting any information yet. 
In the next part of this series we will create the backend for this app and we will also revisit our front end code to implement REST API calls.

Setting up express app

We will start exactly from where we left in the part 1. So far we have a fully functional front end react app, next we need to setup our application's backend, so let's start with installing mondodb locally if you do not have that already. I have prepared this demo app on mongodb version 3.0.5 and node.js version 4.2.3, but it should work fine with older versions as well.

Next navigate to the root directory of our app in command shell and run following commands:
npm install mongoose --python=python2.7 --save
npm install body-parser --save
npm install underscore --save
mongoose is a document object mapper, we will use it to interact with mongodb in our application, we have specified python version explicity to avoid installation issues you might face, if there are more than one versions of python installed in your system. body-parser module is needed to parse http request's body since express.js does not have an in built support for this. underscore module has tons of very useful utility functions which make it easy for us to focus on our application's business logic rather than spending too much time writing utility code.
We are now done with the setup so let's start writting some express code.

Implementing REST endpoints

Add two new directories "data" and "controllers" inside "server" directory of your app. As you might have guessed, "data" directory is going to contain mongoose data models and "controllers" directory will have express routers. In our application there is going to be only one model School so let's add a new file "school.js" in datadirectory and add the following code in it: 
var mongoose = require("mongoose");
var schoolSchema = mongoose.Schema({
    name: String,
    tagline: String
});

module.exports = mongoose.model("school", schoolSchema);
In the above code we have created our very simple model "school" which has only two properties name andtagline of type String. Next let's create our controller, add a new file "schoolController.js" in the controllersdirectory and add the following code in it:
var mongoose = require("mongoose");
var School = require("../data/school");
var _ = require("underscore");

var router = require("express").Router();
router.route("/schools/:id?").get(getSchools).post(addSchool).delete(deleteSchool);

function getSchools(req, res) {
    School.find(function (err, schools) {
        if (err)
            res.send(err);
        else
            res.json(schools);
    });
}

function addSchool(req, res) {
    var school = new School(_.extend({}, req.body));
    school.save(function (err) {
        if (err)
            res.send(err);
        else
            res.json(school);
    });
}

function deleteSchool(req, res) {
    var id = req.params.id;
    School.remove({ _id: id }, function (err, removed) {
        if (err)
            res.send(err)
        else
            res.json(removed);
    });
}

module.exports = router;
In the above code, we have created a new express router which has only one route "/schools/:id?" and for each HTTP verb we have a seperate request handler. We are going to use only GET, POST and DELETE in our application to keep it simple. Our route also has an optional route parameter which we will need in order to identify specific school while deleting it. To interact with the database for CRUD operation we are using ourSchool model which we had created in the previous step.
Also note that in addSchool and deleteSchool functions, we are accessing req.body object which get's populated by the body-parser middleware. We will configure this in the next step. We are using undercore's extend utility function which copies the req.body object to an empty object to populate our model.
Now let's modify "server.js" file as shown below:
var express = require("express");
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
var path = require("path");

//controllers
var schoolController = require("./controllers/schoolController");

//Express request pipeline
var app = express();
app.use(express.static(path.join(__dirname, "../app/dist")));
app.use(bodyParser.json())
app.use("/api", schoolController);

app.listen(7777, function () {
    console.log("Started listening on port", 7777);
});

// Connect to mongodb database
mongoose.connect("mongodb://localhost/schoolfinder");
We have made few changes in server.js file, we need body-parser and mongoose modules, we have configured bodyparser to parse json payloads on http requests, also we have mounted our schoolController to /api route, so any request in the form of /api/schools or /api/schools/xxxx will be handled by schoolController. Further we need to connect to mongodb database using mongoose.connect function. schoolfinder is our database name which will get created automatically when you insert your first record.
Please ensure that mondodb instance is running before you run the app, you can also change the mongodb connection string to a remote mongo server if you want.
So at this point we have our backend APIs ready, let's revisit the react code to implement REST APIs calls.

Plugging REST to react

We need some library to make ajax calls to backend APIs, I will be using JQuery for this, but you can of cource pick your own favorite. We also need a promise library to avoid nested and painful callbacks. Let's install JQueryand es6-promise modules using npm
npm install jquery --save
npm install es6-promise --save
Next add a new directory "services" inside "app" directory and add a new file "schoolService.js". This file is going to contain REST APIs calls, let's add the folloing code in it:
var $ = require("jquery");
var promise = require("es6-promise");
var resourceUrl = "http://localhost:7777/api/schools";

module.exports = {
    addSchool: function (school) {
        var Promise = promise.Promise;
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: resourceUrl,
                data: JSON.stringify(school),
                method: "POST",
                dataType: "json",
                contentType: "application/json",
                success: resolve,
                error: reject
            });
        });
    },
    getSchools: function () {
        var Promise = promise.Promise;
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: resourceUrl,
                method: "GET",
                dataType: "json",
                success: resolve,
                error: reject
            });
        });
    },
    deleteSchool: function (school) {
        var Promise = promise.Promise;
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: resourceUrl + "/" + school._id,
                method: "DELETE",
                dataType: "json",
                success: resolve,
                error: reject
            });
        });
    }
}
Above code has some very familiar JQuery ajax calls, the only thing I want to highlight is, the way we have used Promises. We attach JQuery's success and error handlers to Promise object's resolve and reject callbacks and we return the Promise object itself. You can find more information about Javascript promises here, I am not going to discuss promises here, it deserves it's own separate article.
Now let's modify "schoolsStore.js" and "main.jsx" files as shown below so that our app starts using theschoolService to handle data rather showing the dummy:

schoolsStore.js
var dispatcher = require("../dispatcher");
var schoolService = require("../services/schoolService");

function SchoolStore() {
    var listeners = [];

    function onChange(listener) {
        getSchools(listener);
        listeners.push(listener);
    }
    
    function getSchools(cb){
        schoolService.getSchools().then(function (res) {
            cb(res);
        });
    }

    function addSchool(school) {
        schoolService.addSchool(school).then(function (res) {
            console.log(res);
            triggerListeners();
        });
    }

    function deleteSchool(school) {
        schoolService.deleteSchool(school).then(function (res) {
            console.log(res);
            triggerListeners();
        });
    }

    function triggerListeners() {
        getSchools(function (res) {
            listeners.forEach(function (listener) {
                listener(res);
            });
        });
    }

    dispatcher.register(function (payload) {
        var split = payload.type.split(":");
        if (split[0] === "school") {
            switch (split[1]) {
                case "addSchool":
                    addSchool(payload.school);
                    break;
                case "deleteSchool":
                    deleteSchool(payload.school);
                    break;
            }
        }
    });

    return {
        onChange: onChange
    }
}

module.exports = SchoolStore();
main.jsx
var React = require("react");
var ReactDOM = require("react-dom");
var SchoolsList = require("./components/SchoolsList.jsx");
var schoolsStore = require("./stores/schoolsStore");
var _schools = [];
var getSchoolsCallback = function(schools){
    _schools = schools;
    render();
};
schoolsStore.onChange(getSchoolsCallback);

function render(){
    ReactDOM.render(<SchoolsList schools={_schools} />, document.getElementById("container"));    
}
Now run the gulp command and browse the app, please ensure you have mongodb instance up and running.

Summary

If you have tolerated the article this far then it means you want to learn react. I have attatched the sample code with this article and I encourage you to download and refer to it, in case you face any problems following along. Follow these steps to run the sample:

1. Download and unzip
2. Navigate to the root directory of the extracted app in your command shell
3. Run npm install
4. Run bower install
5. Run gulp
6. Run nodemon .\server\server.js

1 comment:

  1. Being a Web Design agency in sydney I appreciate the article, This article is very useful for Web Designers. Thanks for sharing such a nice article.

    ReplyDelete

Genuine websites to earn money.

If you are interested in PTC sites then this article is for you. I have personally tried many of the sites and found that the best thing ...