Building A Beautiful Mobile Portfolio App With IonicFramework, NodeJs, Cloudinary And MongoDB Part 1



This article shows you how to build an portfolio mobile app using Nodejs, Cloudinary, MongoDB and Ionicframework. I assumed that readers of the this series already have basic knowledge in NodeJS,MongoDB and Ionicframework.

Elements of the App

NodeJS

The API will be written with NodeJS.

Cloudinary

Cloudinary is the media management platform for web and mobile developers, so all the portfolio images will be stored here

MongoDB

The application database will be mongodb

Ionicframework

The mobile app itself will be built using Ionicframework

Let's begin with the API.

Create a folder named mobile-portfolio-nodejs-api and cd into the directory from your favourite command line tool. Run npm init and follow the instructions to generate package.js file.

Modify your package.json file to look like this:

{
  "name": "mobile-portfolio-nodejs-api",
  "version": "1.0.0",
  "description": "A NodeJS API for mobile portfolio app",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [
    "nodejs",
    "api",
    "express"
  ],
  "author": "Adesina Mark Omoniyi",
  "license": "MIT",
  "dependencies": {
    "bcrypt-nodejs": "0.0.3",
    "body-parser": "^1.15.2",
    "cloudinary": "^1.4.4",
    "connect-multiparty": "^2.0.0",
    "cors": "^2.8.1",
    "express": "^4.14.0",
    "mongoose": "^5.1.4"
  },
  "engines": {
    "node": "8.11.2"
  }
}

All the dependencies needed for the project has been included in the package.json file. The next thing is to run npm install to bring in all the dependencies from the package repositories online.

The App Server

Create a file named index.js in the root of the project folder and bring in the basic modules required to run our simple server. Modify the index.js to reflect the following:

var express = require('express'),
     app = express(),
     bodyParser = require('body-parser'),
     cors = require('cors');


app.set('port', (process.env.PORT || 5000));

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());

server.listen(app.get('port'), function () {
     console.log('Node app is running on port', app.get('port'));
});


The code is pretty simple, we created our server using express and we asked the server to listen on port 5000. As it is the app isn't doing anything cool currently.

The MongoDB Database

Let's create the database where all the portfolio app data will be stored. We are going to be using MLab.  This is a Database-as-a-Service for MongoDB, I wont be covering how database can be created in MLab there are lots of articles online that can be of help.

Create the database and name it mobile-portfolio. The next thing is to find a way of connection to the database from within our express app.

Create a folder called configuration in the root of the project folder and add a file named app.config.js, add the code below to the file created.

module.exports = {
     'serverPort':8000,
     'dbUrl':'mongodb://:@ds237409.mlab.com:37409/food-delivery'     
 }

Replace the dbUrl with your own url as copied from MLab dashboard.

Create another folder in the root of the project folder named db-connection and add file named db.connection.js, modify the file like so:
var mongoose = require('mongoose');
var config = require('../configuration/app.config');

mongoose.connect(config.dbUrl);

mongoose.connection.on('connected', function () {
 console.log('Mongoose connected to ' + config.dbUrl);
});
mongoose.connection.on('error',function (err) {
 console.log('Mongoose connection error: ' + err);
});
mongoose.connection.on('disconnected', function () {
 console.log('Mongoose disconnected');
});
process.on('SIGINT', function() {
 mongoose.connection.close(function () {
  console.log('Mongoose disconnected through app termination');
  process.exit(0);
 });
});

Cloudinary Setup

I wont also be covering how to register and setup a free cloudinary account in the article. That can be found on their blog.

After setting up a free account, there three essential information that are needed to enable our app communicate with cloudinary which are api_key, cloud_name and api_secret.

Modify the app.config.js file to reflect the cloudinary settings like so:

module.exports = {
     'serverPort':8000,
     'dbUrl':'mongodb://:@ds237409.mlab.com:37409/food-delivery',
      'cloud_name': 'YOUR_CLOUD_NAME',
     'api_key': 'API_KEY',
     'api_secret': 'YOUR_SECRET'     
 }

Now let's add our configuration to the index.js file like so:
config = require('./configuration/app.config'),
     dbConnection = require('./db-connection/db.connection')

The full code in the index.js now look like this:
var express = require('express'),
     app = express(),
     bodyParser = require('body-parser'),
     config = require('./configuration/app.config'),
     dbConnection = require('./db-connection/db.connection')
     cors = require('cors');


app.set('port', (process.env.PORT || config.serverPort));

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());

server.listen(app.get('port'), function () {
     console.log('Node app is running on port', app.get('port'));
});


Ther Server Route

Currently, if we run the app using node index.js and we try to check our browser via http://localhost:8000 you will see that the app isn't coming up. That is because no route has been defined.

Add a folder called routes and add a file named app.routes.js, add the following code:
module.exports = function (express, app) {

 var router = express.Router();

 router.get('/', function (req, res) {
  res.json("API Home Page");
 })

 app.use('/', router);

}

Then add the this line of code to the index.js file ti fire up the route we just created:
require('./routes/app-routes')(express, app);

If we run node index now our app should be running on port 8000.

The App Models
We are going to create three models namely user, category and portfolio. Add a folder named interface and add three files user.js,category.js and portfolio.js, modify the files like so:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');


var userSchema = new Schema({
    email: { type: String, required: true },
    password: { type: String, required: true },
    firstName: { type: String, default: '' },
    lastName: { type: String, default: '' },
    phone: { type: String, required: true },
    role:{type:String,required:true},
    avatar_url:{type:String,default:''},
    created_at: { type: Date, default: Date.now }
});

userSchema.pre('save', function (next) {
    var user = this;
    if (!user.isModified('password')) return next();
    bcrypt.genSalt(10, function (err, salt) {
        if (err) return next(err);
        bcrypt.hash(user.password, salt, null, function (err, hash) {
            if (err) return next(err);
            user.password = hash;
            next();
        })
    })
})

userSchema.methods.comparePassword = function (password) {
    return bcrypt.compareSync(password, this.password)
}

module.exports = mongoose.model('User', userSchema);

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

var categorySchema = new Schema({
 title: { type: String,required:true },
 created_at: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Category', categorySchema);

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

var portfolioSchema = new Schema({
 author: { type: Schema.Types.ObjectId, ref: 'User' },
 category:{ type: Schema.Types.ObjectId,ref:'Category'},
 title: { type: String },
 image_url: { type: String, default: '' },
 description: { type: String },
 web_url: { type: String, default: '' },
 created_at: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Portfolio', portfolioSchema);

Next, let's add the controllers where the real code will live. We are going to need three controllers,  add a folder named controllers and create three files - category.controller.js, portfolio.controller.js and user.controller.js and add the following code:
var Category = require('../interfaces/category'),
     config = require('../configuration/app.config');

     module.exports = {

          add:(req, res, next)=>{
               var category =new Category({
                    title:req.body.title
               }).save((err, response) => {
                    if (err) {
                         res.status(400).json({ status: 0, message: JSON.stringify(err) });
                    } else {
                         res.status(201).json({
                              status: 1,
                              message: 'Category has been created successfully',
                              data: response
                         });
                    }
               });
          },

          get:(req,res,next)=>{
               Category.find({}, (err, result)=> {
                    if (err) return next(err);
                    res.status(200).json({ status: 1, message: null, count: result.length, data: result });
               });
          }

     }

var User = require('../interfaces/user');

module.exports = {

     register: (req, res, next) => {

          var user = new User({

               email: req.body.email,
               password: req.body.password,
               firstName: req.body.firstName,
               lastName: req.body.lastName,
               phone: req.body.phone,
               role:req.body.role,
               avatar_url:req.body.avatar_url

          }).save((err, response) => {
               if (err) {
                    res.status(400).json({ status: 0, message: JSON.stringify(err) });
               } else {
                    res.status(201).json({
                         status: 1,
                         message: 'User has been created successfully',
                         data: response
                    });
               }
          });
     },

     update: (req, res, next) =>{
          User.findByIdAndUpdate({ _id: req.params.id }, (err, res, next)=> {
               if (err) return next(err);
          });
     },
     login:  (req, res, next) => {
          User.findOne({ email: req.body.email },  (err, result)=> {
               if (err) return next(err);
               res.status(200).json({ status: 1, message: null, count: result.length, data: result });
          });
     },
     get: (req, res, next)=> {
          User.find({}, (err, result)=> {
               if (err) return next(err);
               res.status(200).json({ status: 1, message: null, count: result.length, data: result });
          });
     },
     delete: (req, res, next)=> {
          User.find({}).remove().exec( (err, result) => {
               res.json({ result });
          })
     }



}

var Portfolio = require('../interfaces/portfolio'),
     config = require('../configuration/app.config'),
     cloudinary = require('cloudinary'),
     multipart = require('connect-multiparty')();

cloudinary.config({
     cloud_name: config.cloud_name,
     api_key: config.api_key,
     api_secret: config.api_secret
});

module.exports = {

     add: (req, res, next) => {

          if(!req.files){
               var portfolio = new Portfolio({
                    author: req.body.author_id,
                    category: req.body.category_id,
                    title: req.body.title,
                    image_url: '',
                    description: req.body.description,
                    web_url: req.body.web_url
               }).save((err, response) => {
                    if (err) {
                         res.status(400).json({ status: 0, message: JSON.stringify(err) });
                    } else {
                         res.status(201).json({
                              status: 1,
                              message: 'Portfolio has been created successfully',
                              data: response
                         });
                    }
               });
          }else{

          cloudinary.uploader.upload(req.files.file.path, (resp) => {

               var portfolio = new Portfolio({
                    author: req.body.author_id,
                    category: req.body.category_id,
                    title: req.body.title,
                    image_url: resp.url,
                    description: req.body.description,
                    web_url: req.body.web_url
               }).save((err, response) => {
                    if (err) {
                         res.status(400).json({ status: 0, message: JSON.stringify(err) });
                    } else {
                         res.status(201).json({
                              status: 1,
                              message: 'Portfolio has been created successfully',
                              data: response
                         });
                    }
               });

          });
     }
     },
     getAll: (req, res, next) => {
          Portfolio.find({}, 'category title image_url description web_url')
               .populate('author', 'firstName lastName avatar_url role')
               .sort('-created_at')
               .exec(function (err, result) {
                    if (err) return next(err);
                    res.status(httpCodes.OK).json({ status: 1, message: null, count: result.length, data: result });
                })
     },
     get: (req, res, next) => {

     }



}

Then modify the app.route.js file like so
var userCtrl = require('../controllers/user.controller'),
 catCtrl = require('../controllers/category.controller'),
 portfolioCtrl =require('../controllers/portfolio.controller');
var multipart = require('connect-multiparty')();

module.exports = function (express, app) {

 var router = express.Router();

 router.get('/', function (req, res) {
  res.json("API Home Page");
 })

 //Users API Routes
 router.post('/api/v1/users', multipart, userCtrl.register);
 router.get('/api/v1/users', userCtrl.get);
 router.post('/api/v1/categories',catCtrl.add);
 router.get('/api/v1/categories',catCtrl.get);

 router.post('/api/v1/portfolios',portfolioCtrl.add);
 app.use('/', router);

}



That is it! Our API is ready. In the next article I will walk you through on building the mobile app. Till then happy coding.




No comments:

Powered by Blogger.