Nodejs Rest Api Flutter App

Nodejs Rest Api Flutter App

    Replace GoLang api with Nodejs api

    Here we are going to build app using nodejs rest api for flutter app.

    We will do this locally. So we need to install nodejs, So go ahead and install it from here https://nodejs.org/en/

    We will use nodejs express framework to build our api. Go ahead a make a directory name nodejs-rest-api-flutter

    Go inside the directory and run the below commands

    npm install express mysql cors --save

    It will install the below three modules

    Express, mysql and cors

    1. Express is the nodes framework
    2. Mysql for database
    3. And cors 

    What is CORS? CORS stands for Cross-Origin Resource Sharing . It allows us to relax the security applied to an API. This is done by bypassing the Access-Control-Allow-Origin headers, which specify which origins can access the API.

    Building Node Server

    Inside this nodejs-rest-api-flutter directory make a file called server.js and make another directory called app

    Put the code inside server.js

    const express = require("express");
    const cors = require("cors");
    const app = express();
    
    var corsOptions = {
      origin: "http://localhost:8081"
    };
    app.use(cors(corsOptions));
    // parse requests of content-type - application/json
    app.use(express.json());
    // parse requests of content-type - application/x-www-form-urlencoded
    app.use(express.urlencoded({ extended: true }));
    // simple route
    app.get("/", (req, res) => {
      res.json({ message: "Welcome to dbestech nodejs flutter application." });
    });
    // set port, listen for requests
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}.`);
    });

    Here we want our app to use 8081 port, but if it's not available then it will use 8080. Run the command

    node server.js

    You will see the below message

    Welcome to dbestech nodejs flutter application

     

    Create Mysql Database

    First go ahead and create a database. Call it task_management

    Run the below command to create the database

    CREATE DATABASE task_management;

    And then run again another command to create a table name tasks

    CREATE TABLE IF NOT EXISTS `tasks` (
      id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
     task_name varchar(255) NOT NULL,
     task_detail varchar(255),
      published BOOLEAN DEFAULT false,
     date DATETIME,
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    If you can not create using command line, try to create them using phpmyadmin or mysql work bench.

     

    Database Config

    After that create a new folder inside the app. Name it config and then cd to config folder and create a new file name db.config.js. In this folder put the below code 

    module.exports = {
    
      HOST: "localhost",
    
      USER: "root",
    
      PASSWORD: "123456",
    
      DB: “task_management”
    
    };

     

    Creating Database Model

    After that, we need to connect with the database. For this reason, inside app folder, we will create a new folder name models. Cd to the models folder and create a new file called db.js and inside this put the code below

    const mysql = require("mysql");
    
    const dbConfig = require("../config/db.config.js");
    
    // Create a connection to the database
    
    const connection = mysql.createConnection({
    
      host: dbConfig.HOST,
    
      user: dbConfig.USER,
    
      password: dbConfig.PASSWORD,
    
      database: dbConfig.DB
    
    });
    
    // open the MySQL connection
    
    connection.connect(error => {
    
      if (error) throw error;
    
      console.log("Successfully connected to the database.");
    
    });
    
    module.exports = connection;

     

    Creating A Task Model

    We need to create a task model that will represent what’s inside the database and we can operate on the database table task.

    Our model will do the below things

    1. create a new Task
    2. find a Task by id
    3. get all Tasks
    4. get all published Tasks
    5. update a Task by id
    6. remove a Task
    7. remove all Tasks
    const sql = require("./db.js");
    // constructor
    const Task = function(task) {
      this.task_name = task.task_name;
      this.task_detail = task.task_detail;
      this.date = task.date;
      this.published=task.published;
    };
    Task.create = (newTask, result) => {
      sql.query("INSERT INTO tasks SET ?", newTask, (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(err, null);
          return;
        }
        console.log("created task: ", { id: res.insertId, ...newTask });
        result(null, { id: res.insertId, ...newTask });
      });
    
    };
    Task.findById = (id, result) => {
      console.log("The id is",id);
      sql.query(`SELECT * FROM tasks WHERE id = ${id}`, (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(err, null);
          return;
        }
        if (res.length) {
          console.log("found task: ", res[0]);
          result(null, res[0]);
          return;
        }
        // not found Task with the id
        result({ kind: "not_found" }, null);
      });
    
    };
    Task.getAll = (name, result) => {
      let query = "SELECT * FROM tasks";
      if (name) {
        query += ` WHERE task_name LIKE '%${name}%'`;
      }
      sql.query(query, (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(null, err);
          return;
        }
        console.log("tasks: ", res);
        result(null, res);
      });
    };
    Task.getAllPublished = result => {
      sql.query("SELECT * FROM tasks WHERE published=1", (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(null, err);
          return;
        }
        console.log("tasks: ", res);
        result(null, res);
      });
        
    };
    Task.updateById = (id, task, result) => {
      sql.query(
        "UPDATE tasks SET task_name = ?, task_detail = ?, published = ? WHERE id = ?",
        [task.task_name, task.task_detail, task.published, id],
        (err, res) => {
          if (err) {
            console.log("error: ", err);
            result(null, err);
            return;
          }
          if (res.affectedRows == 0) {
            // not found Task with the id
            result({ kind: "not_found" }, null);
            return;
          }
          console.log("updated task: ", { id: id, ...task });
          result(null, { id: id, ...task });
        }
      );
    
    };
    Task.remove = (id, result) => {
      sql.query("DELETE FROM tasks WHERE id = ?", id, (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(null, err);
          return;
        }
        if (res.affectedRows == 0) {
          // not found Task with the id
          result({ kind: "not_found" }, null);
          return;
        }
        console.log("deleted task with id: ", id);
        result(null, res);
      });
    };
    Task.removeAll = result => {
      sql.query("DELETE FROM tasks", (err, res) => {
        if (err) {
          console.log("error: ", err);
          result(null, err);
          return;
        }
        console.log(`deleted ${res.affectedRows} tasks`);
        result(null, res);
      });
    };
    module.exports = Task;

    Inside this model we used sql.query() to run all the database query. The queries are basic create, delete, updating and select. 

    You will also see that, every function just returns a result function. result function contains null, err or res. 

    We send null when there's nothign to send, and err when errors found and res when we have a good response.

    Define Routes

    Now let’s define routes. To do that, let’s create a new folder inside app folder and name it routes. And inside that app folder create a new file name task.routes.js

    This routes file will help us to point to the end point from our app. 

    These are routes we define. They also represent our endoints 

    1. /tasks: GET, POST, DELETE
    2. /tasks/one:  GET
    3. /tasks/update: PUT
    4. tasks/delete/:DELETE
    module.exports = app => {
      const tasks = require("../controllers/task.controller.js");
      var router = require("express").Router();
      // Create a new Task
      router.post("/", tasks.create);
      // Retrieve all tasks
      router.get("/", tasks.findAll);
      // Retrieve all published tasks
      router.get("/published", tasks.findAllPublished);
      // Retrieve a single Task with id
      router.get("/one", tasks.findOne);
      // Update a Task with id
      router.put("/update", tasks.update);
      // Delete a Task with id
      router.delete("/delete", tasks.delete);
      // Delete all tasks
      router.delete("/", tasks.deleteAll);
      app.use('/api/tasks', router);
    };

    Define Controller

    var qs = require('querystring');
    const Task = require("../models/task.model.js");
    // Create and Save a new Task
    
    exports.create = (req, res) => {
      console.log(req.body);
      // Validate request
      if (!req.body) {
        res.status(400).send({
          message: "Content can not be empty!"
        });
      }
      // Create a Task
      const task = new Task({
        task_name: req.body.task_name,
        task_detail: req.body.task_detail,
        date: req.body.date,
        published:req.body.published || 0
      });
      // Save Task in the database
      Task.create(task, (err, data) => {
        if (err)
          res.status(500).send({
            message:
              err.message || "Some error occurred while creating the Task."
          });
        else res.send(data);
      });
    };
    // Retrieve all tasks from the database (with condition).
    exports.findAll = (req, res) => {
      const title = req.query.name;
      Task.getAll(title, (err, data) => {
        if (err)
          res.status(500).send({
            message:
              err.message || "Some error occurred while retrieving tasks."
          });
        else res.send(data);
      });
    };
    exports.findAllPublished = (req, res) => {
      Task.getAllPublished((err, data) => {
        if (err)
          res.status(500).send({
            message:
              err.message || "Some error occurred while retrieving tasks."
          });
        else res.send(data);
      });
    
    
    };
    // Find a single Task with a id
    exports.findOne = (req, res) => {
      console.log(req.query.id);
      Task.findById(req.query.id, (err, data) => {
        if (err) {
          if (err.kind === "not_found") {
            res.status(404).send({
              message: `Not found Task with id ${req.query.id}.`
            });
          } else {
            res.status(500).send({
              message: "Error retrieving Task with id " + req.params.id
            });
          }
        } else res.send(data);
      });
    };
    
    // Update a Task identified by the id in the request
    exports.update = (req, res) => {
      // Validate Request
      if (!req.body) {
        res.status(400).send({
          message: "Content can not be empty!"
        });
      }
    
    
      console.log(req.body);
      Task.updateById(
        req.query.id,
        new Task(req.body),
        (err, data) => {
          if (err) {
            if (err.kind === "not_found") {
              res.status(404).send({
                message: `Not found Tutorial with id ${req.query.id}.`
              });
            } else {
              res.status(500).send({
                message: "Error updating Tutorial with id " + req.query.id
              });
            }
          } else res.send(data);
        }
      );
    
    };
    // Delete a Task with the specified id in the request
    exports.delete = (req, res) => {
      Task.remove(req.query.id, (err, data) => {
        if (err) {
          if (err.kind === "not_found") {
            res.status(404).send({
              message: `Not found Task with id ${req.query.id}.`
            });
          } else {
            res.status(500).send({
              message: "Could not delete Task with id " + req.query.id
            });
          }
        } else res.send({ message: `Task was deleted successfully!` });
      });
    
    };
    // Delete all tasks from the database.
    exports.deleteAll = (req, res) => {
      Task.removeAll((err, data)=>{
        if(err){
          res.status(500).send({
            message:err.message || "Could not finish the operation"
          });
    
        }else{
          res.send({
            message:"Removed all task successfully"
          });
        }
      })
    };

    Controller would sit between the routes and models. From our app or webapp, nodejs server will be hit, first time it will hit the end points and each end point will find specific method in the controller and inside this method, it will find a method that exist in the model.