Introduction
Full stack application development with front-end technologies
Tech stacks
- Package Manager NodeJS: nodejs
- REST API: expressjs
- Persistence storage: mongoDB
- AngularJS: AngularJS
Backend setup and configuration
Initialization
- Create
api-server
folder infullstack-development
folder and initializeapi-server
open terminal and type
$ npm init
- Open
package.json
and copy below code in it
{
"name": "api-server",
"version": "1.0.0",
"description": "fullstack application development with front-end technologies",
"main": "api.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/pradeep1991singh/fullstack-development"
},
"keywords": [
"fullstack",
"application",
"development",
"front-end",
"only",
"technologies"
],
"author": "pradeep singh",
"license": "ISC",
"dependencies": {
"body-parser": "^1.16.0",
"express": "^4.14.0",
"mongoose": "^4.7.7",
"nodemon": "^1.11.0"
}
}
- So, basically above we are defining api-server information related to version, dependencies etc.
- Main part is
dependencies
section. We are defining api-server dependencies which is - body-parser : for api middleware, handling in-coming request
- express : for serving REST API
- mongoose : for mongodb object modeling
- nodemon : for reloading node server automaticaly
Installation
- Switch to api-server root and install all dependencies mentioned in
package.json
open terminal and type
$ npm install
Server structure
fullstack-development/
--- api-server/
------ api.js
------ Todo.model.js
------ package.json
Build api-server
- We will use mongoDB for persistence back-end data storage.
- Install mongoDB
- Run mongoDB, start two terminal, one for mongoDB server and other for mongoDB shell
- First terminal (run mongoDB server)
$ mongond
- Second terminal (run mongoDB shell)
$ mongo
- Create new db
mydb
and new collectiontodos
. In mongoDB we have collections in place of tables - documentation - Create a new file
api-server.js
and paste below code in that
// api configuration
// express server configuration
var express = require('express');
var api = express();
// body configuration for handling middleware
var bodyParser = require('body-parser');
// mongoose(mongoDB database) configuration
var mongoose = require('mongoose');
var Todo = require('./Todo.model');
// api port, api will be running on 8080
var port = 8080;
// connect to mongoDB
var db = 'mongodb://localhost/mydb';
mongoose.connect(db);
// bodyParser configuration
api.use(bodyParser.json());
api.use(bodyParser.urlencoded({
extended: true
}));
// enable cors
api.all('/*', function(req, res, next) {
console.log('request made for: %s', req.originalUrl);
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,OPTIONS,DELETE');
next();
});
// api root
api.get('/', function(req, res) {
res.send('api running... <br> please use "/api/todos" for getting all todos ');
});
// api listen
api.listen(port, function() {
console.log('api listening on port ' + port);
});
- We are serving a mongoDB api server on port 8080
Run api server
- Switch
fullstack-development/api-server
folder open terminal and type
$ nodemon
- Now you should able to see your api server running at http://localhost:8080/
- Lets add few Rest api end-point for front-end todo applicaton. Paste below code in
api-server.js
betweenapi root
andapi listen
section.
// get list of todos
api.get('/api/todos', function(req, res) {
console.log('getting all todos');
Todo.find({})
.exec(function(error, todos) {
if (error) {
console.log('error getting list');
} else {
console.log(todos);
res.json(todos);
}
});
});
// get particular single todo
api.get('/api/todos/:id', function(req, res) {
Todo.findOne({
_id: req.params.id
})
.exec(function(error, todo) {
if (error) {
console.log('error getting');
} else {
console.log(todo);
res.json(todo);
}
})
});
// add new todo
api.post('/api/todos', function(req, res) {
Todo.create(req.body, function(error, todo) {
if (error) {
res.send('error saving todo');
} else {
console.log(todo);
res.send(todo);
}
});
});
// update todo
api.put('/api/todos/:id', function(req, res) {
Todo.findOneAndUpdate({
_id: req.params.id
},
{$set: {status: req.body.status}},
{upsert: true },
function(error, todo) {
if (error) {
console.log('error updating');
} else {
console.log(todo);
res.sendStatus(204);
}
});
});
// remove todo
api.delete('/api/todos/:id', function(req, res) {
Todo.findOneAndRemove({
_id: req.params.id
}, function(error, todo) {
if (error) {
console.log('error deleting');
} else {
console.log(todo);
res.sendStatus(204);
}
})
});
- Now you have your api server listening at 8080 and running with required api end-points. Lets switch to front-end application now.
Front-end setup and configuration
Initialization
- Create
angular-app
folder infullstack-development
folder and initialize it withnpm init
- Open
package.json
and copy below code in it
{
"name": "todo",
"version": "1.0.0",
"description": "todo app written in angular 1",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/pradeep1991singh/fullstack-development/angular-app.git"
},
"keywords": [
"todo",
"app",
"angularjs",
"1",
"front-end",
"mobile",
"application",
"full",
"stack",
"development"
],
"author": "pradeep singh",
"license": "ISC",
"bugs": {
"url": "https://github.com/pradeep1991singh/fullstack-development/angular-app/issues"
},
"homepage": "hhttps://github.com/pradeep1991singh/fullstack-development/angular-app#readme",
"devDependencies": {
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1",
"gulp-inject": "^4.2.0",
"gulp-natural-sort": "^0.1.1",
"gulp-rename": "^1.2.2",
"gulp-sass": "^3.1.0",
"gulp-webserver": "^0.9.1",
"run-sequence": "^1.2.2"
}
}
Installation
- Switch to angular-app root and install all devDependencies mentioned in
package.json
. - It will install gulp and required gulp packages for serving angular app open terminal and type
$ npm install
Setup angular-app
- Basically we will be creating a simple todo application in angular and will consume REST api end-points offered by api-server running at http://localhost:8080/.
App structure
fullstack-development/
--- angular-app/
------ app/
--------- scripts/
------------ controllers/
--------------- todo-list.controller.js
--------------- todo-details.controller.js
------------ services/
--------------- todo.service.js
------------ app.js
--------- views/
------------ todo-list.html
------------ todo-details.html
--------- styles/
------------ styles.css
--------- index.html
--------- bower.json
--------- gulpfile.js
--------- package.json
Build front-end app
- Create index.html which will be our main entry-point file for serving our application.
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" ng-app="todo"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Todo app</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- inject:css -->
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="/app/styles/main.css">
<!-- endinject -->
<!-- inject:js -->
<script src="/bower_components/angular/angular.js"></script>
<script src="/bower_components/angular-resource/angular-resource.js"></script>
<script src="/bower_components/angular-route/angular-route.js"></script>
<script src="/app/scripts/app.js"></script>
<script src="/app/scripts/controllers/todo-details.controller.js"></script>
<script src="/app/scripts/controllers/todo-list.controller.js"></script>
<script src="/app/scripts/directives/todo-list.directive.js"></script>
<script src="/app/scripts/services/todo.service.js"></script>
<!-- endinject -->
</head>
<body>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<div class="col-xs-12" ng-view></div>
</body>
</html>
- In
index.html
we have some bower dependencies lets createbower.json
file.
{
"name": "todo",
"description": "todo app written in angular 1",
"main": "index.html",
"authors": [
"pradeep singh"
],
"license": "ISC",
"keywords": [
"todo",
"app",
"angularjs",
"1",
"front-end",
"mobile",
"application",
"full",
"stack",
"development"
],
"homepage": "",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "^1.6.1",
"angular-route": "^1.6.1",
"bootstrap": "^3.3.7",
"angular-resource": "^1.6.1"
}
}
- Install all bower dependencies open terminal and type
bower install
- Lets bootstrap our angular-app, create
app.js
file
angular
.module('todo', ['ngRoute', 'ngResource'])
.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/todo-list.html',
controller: 'todoListController'
})
.when('/todo/:id', {
templateUrl: 'views/todo-details.html',
controller: 'todoDetailsController'
})
.otherwise({
redirectTo: '/'
})
});
- We will be having two views
todo-list
andtodo-details
and conrreponding controllers - Create
todo-list.html
inviews
folder
<h3></h3>
<h4>Create new todo</h4>
<form>
<div class="form-group">
<input type="text" class="form-control" id="exampleInputEmail1" placeholder="title" ng-model="title">
</div>
<div class="form-group">
<textarea class="form-control" rows="3" placeholder="description" ng-model="body"></textarea>
</div>
<button type="button" class="btn btn-default" ng-click="newTodo()">Create</button>
</form>
<hr/>
<h4>Todo lists</h4>
<div class="list-group">
<a href="javascript:void(0)" class="list-group-item" ng-repeat="todo in todoList" ng-click="todoDetails(todo)">
<span class="badge"></span>
</a>
</div>
- Create conrreponding
todo-list.controller.js
controller inscripts/controllers
angular
.module('todo')
.controller('todoListController', function($scope, TodoService, $location) {
$scope.welcomeMessage = "Welcome to todo application";
// get todo list
$scope.todoList = [];
TodoService.list().then(function(response) {
$scope.todoList = response;
},
function(error) {
console.log(error);
});
// add new todo handler
$scope.newTodo = function() {
var newTodo = {
title: $scope.title,
body: $scope.body,
status: 'todo'
};
$scope.todoList.push(newTodo);
TodoService.newTodo(newTodo).then(function(response) {
console.log(response);
},
function(error) {
console.log(error);
});
};
$scope.todoDetails = function(todo) {
$location.path('/todo/' + todo._id);
};
});
- We have a
TodoService
in our controller, let createscripts/services/todo.service.js
for that.
angular
.module('todo')
.service('TodoService', function($q, $resource, $httpParamSerializerJQLike) {
var baseUrl = 'http://localhost:8080/api';
var Todo = $resource(baseUrl + '/todos/:id', {id: '@id'}, {
new: {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for (var param in obj) {
str.push(encodeURIComponent(param) + '=' + encodeURIComponent(obj[param]));
}
return str.join('&');
},
}
});
this.list = function() {
var defer = $q.defer();
Todo.query(function(response) {
defer.resolve(response);
}, function(error) {
defer.reject(error);
});
return defer.promise;
};
this.newTodo = function(newTodo) {
var defer = $q.defer();
Todo.new(newTodo, function(response) {
defer.resolve(response);
}, function(error) {
defer.reject(error);
});
return defer.promise;
};
this.get = function(id) {
var defer = $q.defer();
Todo.get({id: id}, function(response) {
defer.resolve(response);
}, function(error) {
defer.reject(error);
});
return defer.promise;
};
this.delete = function(id) {
var defer = $q.defer();
Todo.delete({id: id}, function(response) {
defer.resolve(response);
}, function(error) {
defer.reject(error);
});
return defer.promise;
};
});
- Above we are consuming api create in api-server section and running at http://localhost:8080/.
- Lets create
views/todo-details.html
for displaying ourtodo-details
Package
<h3>Todo details page</h3>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"></h3>
</div>
<div class="panel-body">
<p></p>
<p>
<span>Status: </span>
</p>
<button type="button"
class="btn btn-default"
ng-if="todo.status!='done'"
ng-click="done()">
Done
</button>
</div>
</div>
angular
.module('todo')
.controller('todoDetailsController', function($scope, TodoService, $routeParams, $location) {
// get todo
TodoService.get($routeParams.id).then(function(response) {
$scope.todo = response;
},
function(error) {
console.log(error);
});
// delete todo handler
$scope.done = function() {
TodoService.delete($routeParams.id).then(function(response) {
$location.path('/');
},
function(error) {
console.log(error);
});
};
});
Run angular-app
- We will use
gulp
for servering and building our angular-app. - Create
gulpfile.js
inangular-app
folder
var gulp = require('gulp');
var inject = require('gulp-inject');
var webserver = require('gulp-webserver');
var naturalSort = require("gulp-natural-sort");
var runSequence = require('run-sequence');
var appBaseUrl = 'http://localhost:8000/app/index.html';
gulp.task('inject', function () {
var target = gulp.src('./app/index.html');
// It's not necessary to read the files (will speed up things), we're only after their paths:
var sources = gulp
.src(['./bower_components/angular/angular.js',
'./bower_components/angular-route/angular-route.js',
'./bower_components/angular-resource/angular-resource.js',
'./app/**/*.js',
'./bower_components/bootstrap/dist/css/bootstrap.css',
'./app/**/*.css'
], {
read: false
})
.pipe(naturalSort());
return target
.pipe(inject(sources))
.pipe(gulp.dest('./app'));
});
gulp.task('serve', function() {
gulp.src('.')
.pipe(webserver({
livereload: true,
directoryListing: true,
open: appBaseUrl
}));
});
gulp.task('default', function() {
// place code for your default task here
runSequence(
'inject',
'serve'
);
});
- Lets run our app using
gulp
, open new terminal and type (Note our api server should be running)
$ gulp
- You should be seeing an angular-app running, Create new todo and those will be start listing under Todo lists.
Summary
Fork code at fullstack-development