Tuesday, September 28, 2021

Use Multiple Datatype in Single Variable on Typescript - Union Type

Typescript have concept Union Type to allow assign multiple datatypes/types for single variable. 

Syntax :

let myVar: string | number

Use Pipe '|' symbol between two types. Here the variable myVar accepting both string and numbers. Union type is useful for to avoid/reduce the use of any type in our code.

I hope this useful for you. Happy Coding.

Friday, September 24, 2021

Implement Local Notifications in Ionic with Capacitor and Example

I started this topic directly from local notification installation. I assume already have angular and ionic setup on your project. Checkout here to complete installation setup.

#Install


npm install @capacitor/local-notifications npx cap sync

#Basic Configuration


Local Notifications needs to be configured with the following options: SmallIcon, IconColor and sound for capactior.

#Example

Add this below json in capacitor.config.json. If need you can change the icon, color and sound.

{ "plugins": { "LocalNotifications": { "smallIcon": "ic_stat_icon_config_sample", "iconColor": "#488AFF", "sound": "notification.wav" } } }

Note : Need to paste the custom icon and sound file in path specified below. then only the sound will work. Icon folder : project-folder/android/app/src/main/res/drawable Sound Folder : project-folder/android/app/src/main/res/raw If you don’t have a folder name with raw in res, then you can create the folder raw inside res. Then paste the sound inside raw.  

Once the above configuration is done, Create Service using the below command. If you create notification as service means you can call this anywhere from your application just use of dependency injection. 

ng g service localnotification

Once created, Imports the local notification package into the service.

import { LocalNotifications } from '@capacitor/local-notifications';


#Check Permission

Need to check notification permission before create notification

return LocalNotifications.checkPermissions().then((res) => { if (res && res.display && res.display == 'denied') { LocalNotifications.requestPermissions().then((res) => { if (res && res.display && res.display == 'denied') { console.log("Need a Notification Permission to Set Reminder."); } }) } });

Both checkPermissions() and requestPermissions() functions return any one state as mentioned below,

'prompt' 'prompt-with-rationale' 'granted' 'denied'



#Create Notification

await LocalNotifications.schedule({ notifications: [{ id: id, title: title, body: description, schedule: { at: new Date(new Date(dateTime).getTime()), }, sound: 'notification.wav' }] });

In notification, 

id should be an integer and unique.  

title Provide the title which you want to show on notification

body Provide the body content which you want to show on notification

schedule Provide the date with time when you want to show the notification. I just used at in my schedule. But in capacitors there will be more options available like on, repeats, every. You can use this option based on your requirement. 

sound if you want to set some custom sound means provide just name of the file with extension .wav (no need to provide file path here), otherwise remove this sound from local notification array, notification rings with default sound.

Note : Need to paste the custom sound file in path below specified. then only the sound will work. Sound File : project-folder/android/app/src/main/res/raw If you don’t have a folder name with raw in res, then you can create the folder raw inside res. Then paste the sound inside raw.


#Example


Below the Service file I created for local notification.

import { Injectable } from '@angular/core';

import { LocalNotifications } from '@capacitor/local-notifications';


@Injectable({

  providedIn: 'root'

})


export class NotificationService {


  constructor() {

    this.checkPermission();

  }


  checkPermission() {

    return LocalNotifications.checkPermissions().then((res) => {

       if (res && res.display && res.display == 'denied') {

         LocalNotifications.requestPermissions().then((res) => {

           if (res && res.display && res.display == 'denied') {

             this.alert.presentToast("Need a Notification Permission to Set Reminder.");

           }

         })

       }

     });

  }


  async scheduleNotification(id: number, title: string, dateTime: any, description: string) {

    await LocalNotifications.schedule({

      notifications: [{

        id: id,

        title: title,

        body: description,

        schedule: {

          at: new Date(new Date(dateTime).getTime())

        },

        sound: 'notification.wav'

      }]

    });

  }

 

Add above file into the service folder and Inject into the component and call scheduleNotification function with proper parameters.


If you have any queries, reach me with a comment.

 

Tuesday, September 21, 2021

Building Simple Rest API for CRUD using NodeJS, Express and MongoDB with JWT Tokens Authentication

Before going to the main topic, we need to install basic stuff. If you already installed everything you can skip and move to the next steps.


Step 1: Install Node, NPM and MongoDB


#1. Node and NPM :


Check if you have already installed Node and NPM on your system using the below command.


node -v

npm -v


if you have these things you will get a version for both like below, Otherwise you need to install. 


C:\Users\ELCOT>node -v

v14.17.3


C:\Users\ELCOT>npm -v

6.14.13

Download and Install the Node from this link here. NPM automatically install with node package.

#2. MongoDB: 

Download and Install Mongo Using this link here.

Step 2: Install NPM dependency Packages

Once Node and NPM are ready, We need to install some dependency packages to run and connect mongodb using node. Before that I need to create and initiate the node project.

npm init

Once you initialize the project, you have the package.json file in the folder.  Now we have started to install dependency packages. 

npm install express --save

npm install body-parser --save

npm install jsonwebtoken --save

npm install mongoose --save 

npm install nodemon --save


Use of these packages :

Express : Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

Body Parser : Node.js body parsing middleware.

Parse incoming request bodies in a middleware before your handlers, available under the req.body property.

Note As req.body's shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.body.foo.toString() may fail in multiple ways, for example the foo property may not be there or may not be a string, and toString may not be a function and instead a string or other user input.

Mongoose : Mongoose is a Node. js based Object Data Modeling (ODM) library for MongoDB. It is akin to an Object Relational Mapper (ORM) such as SQLAlchemy for traditional SQL databases. The problem that Mongoose aims to solve is allowing developers to enforce a specific schema at the application layer.

Nodemon : nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected. 

Step 3 : Building Rest API for Simple CRUD Operation with JWT Tokens Authentication


Below code structure i'm following, If you need you can follow with your wish.



src/controllers/auth.js


const express = require('express')

const config = require('../../db.config');

const router = express.Router();

const User = require('../models/user.model');

const jwt = require('jsonwebtoken');

 

router.post('/', function (req, res) {

    User.findOne({ email: req.body.email }, function (err, user) {

        if (err) {

            return res.status(500).send('Error to connecting server.');

        }

        if (!user) {

            return res.status(404).send('User Not found.');

        }

        var isValidPassword = req.body.password == user.password ? true : false;

        if (!isValidPassword) {

            return res.status(401).send({ auth: false, token: null })

        };

        var token = jwt.sign({ id: user._id }, config.secret, {

            expiresIn: 3600

        });

        res.status(200).send({

            auth: true, token: token

        });

    });

});

 

module.exports = router;


src/controllers/user.js

const express = require('express')

const router = express.Router()

var jwt = require('jsonwebtoken');

var config = require('../../db.config');

const User = require('../models/user.model');

 

router.post('/', authenticationToken, function (req, res) {

    if (!req.body) {

        return res.status(400).send({

            message: "Please fill all required fields"

        });

    }

 

    const user = new User({

        firstName: req.body.firstName,

        lastName: req.body.lastName,

        email: req.body.email,

        phone: req.body.phone,

        userName: req.body.userName,

        password: req.body.password

    });

 

    user.save()

        .then(data => {

            res.send(data);

        }).catch(err => {

            res.status(500).send({

                message: err.message || "Getting error while creating new user."

            });

        });

});

 

router.get('/', authenticationToken, function (req, res) {

    User.find().then(users => {

        res.send(users);

    }).catch(err => {

        res.status(500).send({

            message: err.message || "Getting error while fetching users."

        });

    });

});

 

router.get('/:id', authenticationToken, function (req, res) {

    User.findById(req.params.id)

        .then(user => {

            if (!user) {

                return res.status(404).send({

                    message: "User not found with id " + req.params.id

                });

            }

            res.send(user);

        }).catch(err => {

            if (err.kind === 'ObjectId') {

                return res.status(404).send({

                    message: "User not found with id " + req.params.id

                });

            }

            return res.status(500).send({

                message: "Error getting user with id " + req.params.id

            });

        });

});

 

router.put('/:id', authenticationToken, function (req, res) {

    if (!req.body) {

        return res.status(400).send({

            message: "Please fill all required fields"

        });

    }

 

    User.findByIdAndUpdate(req.params.id, {

        firstName: req.body.firstName,

        lastName: req.body.lastName,

        email: req.body.email,

        phone: req.body.phone,

        userName: req.body.userName,

        password: req.body.password

    }, { new: true })

        .then(user => {

            if (!user) {

                return res.status(404).send({

                    message: "user not found with id " + req.params.id

                });

            }

            res.send(user);

        }).catch(err => {

            if (err.kind === 'ObjectId') {

                return res.status(404).send({

                    message: "user not found with id " + req.params.id

                });

            }

            return res.status(500).send({

                message: "Error updating user with id " + req.params.id

            });

        });

});

 

router.delete('/:id', authenticationToken, function (req, res) {

    User.findByIdAndRemove(req.params.id)

        .then(user => {

            if (!user) {

                return res.status(404).send({

                    message: "user not found with id " + req.params.id

                });

            }

            res.send({ message: "user deleted successfully!" });

        }).catch(err => {

            if (err.kind === 'ObjectId' || err.name === 'NotFound') {

                return res.status(404).send({

                    message: "user not found with id " + req.params.id

                });

            }

            return res.status(500).send({

                message: "Could not delete user with id " + req.params.id

            });

        });

});

 

function authenticationToken(req, res, next) {

    var token = req.headers['x-access-token'];

    if (!token) {

        return res.status(403).send({

            auth: false, message: 'Please Provide the token.'

        });

    }

    jwt.verify(token, config.secret, function (err, decoded) {

        if (err) {

            return res.status(500).send({

                auth: false, message: 'Failed to authenticate token.'

            });

        }

        req.userId = decoded.id;

        next();

    });

}

 

module.exports = router;



src/models/user.model.js


const mongoose = require('mongoose');

 

const UserSchema = mongoose.Schema({

    firstName: String,

    lastName: String,

    email: String,

    phone: String,

    userName: String,

    password: String

}, {

    timestamps: true

});

 

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



src/db.config.js


module.exports = {

    secret: 'simpleCrud',

    url: 'mongodb://localhost:27017/simple-crud'

}



src/server.js


const express = require('express');

const bodyParser = require('body-parser');

 

const app = express();

const port = process.env.PORT || 4000;

 

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

app.use(bodyParser.json())

 

const dbConfig = require('./db.config');

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

mongoose.connect(dbConfig.url, {

    useNewUrlParser: true

}).then(() => {

    console.log("Connected Successfully");

}).catch(err => {

    console.log('Unable to connect the database.', err);

    process.exit();

});

 

const userController = require("./src/controllers/user")

app.use('/api/users', userController)

 

const authController = require('./src/controllers/auth')

app.use('/api/auth', authController)

 

app.listen(port, () => {

    console.log(`Node server is listening on port ${port}`);

});



Once every code changes ready, Please run mongodb using command


mongod


and then run node js using command 


node server.js


Now your API is ready. Node run in the default port 4000. You can call the API using any tool like postman. (http://localhost:4000/api/login , http://localhost:4000/api/user)


Note : We need to send the token on Header with param x-access-token for all API. You're getting a token on the Login API response. Right now the token expires in 1 hour. If you need, you update the expiration time on auth.js.


 If you face any issue or clarification, Please hit me with comments. Thanks!