How to connect to MEAN stack REST api using swift 3 for iOS

Question

I'm trying to create a simple login application with iOS, which uses a MEAN stack server exposing a REST API for the iOS side to connect to.

I've been working on the server side and have an API which allows one to create a user with an Email and Password. I've also created DELETE and GET requests, following this tutorial: https://codeforgeek.com/2015/08/restful-api-node-mongodb/

However, I'm unsure of how to now log in with this information on the iOS side. a few questions I have are:

  • Do I need to create a token for the iOS side to accept?
  • Do I need an Authenticate method?

I've included the code I have for the server and my iOS side below.

I'm quite new to both languages so any help would be greatly appreciated. Thank you in advance.

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');
var app = express();

app.use( bodyParser.json() );       // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
  extended: true
})); 
// view engine setup
// all views passed through views 
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');


app.get('/javascript/jquery.min.js', function (req, res) {
        res.sendFile( __dirname + "/javascript" + "/jquery.min.js" );

});
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

app.post('/', function(req, res) {
  console.log(req.body);
  res.send(200);

  });

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

 //app.use('/',router);


module.exports = app;

index.js

var express = require('express');
var router = express.Router();
var exec = require('child_process').exec;
var util = require('util')
var bodyParser = require('body-parser');
var app = express();

//needed to be able to run child_proccess
app.get('/javascript/jquery.min.js', function (req, res) {
        res.sendFile( __dirname + "/javascript" + "/jquery.min.js" );

});

router.get('/', function(req, res){
  res.render('index', {
    title: 'Home'
  });
});


/** bodyParser.urlencoded(options)
 * Parses the text as URL encoded data (which is how browsers tend to send form data from regular forms set to POST)
 * and exposes the resulting object (containing the keys and values) on req.body
 */
router.use(bodyParser.urlencoded({
    extended: true
}));

/**bodyParser.json(options)
 * Parses the text as JSON and exposes the resulting object on req.body.
 */
router.use(bodyParser.json());

router.post('/unLock', function(req, res){
    console.log("unlocking");  //print to console when the lock is being operated
    // console.log(req.body.paramString); //this doesnt work, trying to get the app to print to console
exec('ssh pi@192.168.2.2 sudo python /home/pi/unlock.py', (e, stdout, stderr)=> { 
    if (e instanceof Error) {
        console.error(e);
        throw e;
    }
})
});

router.post('/Lock', function(req, res){
    console.log("locking"); //print to console when the lock is being operated  
exec('ssh pi@192.168.2.2 sudo python /home/pi/lock.py', (e, stdout, stderr)=> { 
    if (e instanceof Error) {
        console.error(e);
        throw e;
    }
})
});


module.exports = router;

users.js

var express = require('express');
var router = express.Router();
var mongoOp = require("../model/mongo");

router.route("/")
.get(function(req,res){
        var response = {};
        mongoOp.find({},function(err,data){
        // Mongo command to fetch all data from collection.
            if(err) {
                response = {"error" : true,"message" : "Error fetching data"};
            } else {
                response = {"error" : false,"message" : data};
            }
            res.json(response);
        });
    })
//create new user
      .post(function(req,res){
        var db = new mongoOp();
        var response = {};
        // fetch email and password from REST request.
        // Add strict validation when you use this in Production.
        db.userEmail = req.body.email; 
        // Hash the password using SHA1 algorithm.
        db.userPassword =  require('crypto')
                          .createHash('sha1')
                          .update(req.body.password)
                          .digest('base64');
        db.save(function(err){
        // save() will run insert() command of MongoDB.
        // it will add new data in collection.
            if(err) {
                response = {"error" : true,"message" : "Error adding data"};
            } else {
                response = {"error" : false,"message" : "Data added"};
            }
            res.json(response);
        });
    });
//get by id using GET http://localhost:3000/users/id
      router.route("/:id")
    .get(function(req,res){
        var response = {};
        mongoOp.findById(req.params.id,function(err,data){
        // This will run Mongo Query to fetch data based on ID.
            if(err) {
                response = {"error" : true,"message" : "Error fetching data"};
            } else {
                response = {"error" : false,"message" : data};
            }
            res.json(response);
        });
    })
    //update data of a user
    .put(function(req,res){
        var response = {};
        // first find out record exists or not
        // if it does then update the record
        mongoOp.findById(req.params.id,function(err,data){
            if(err) {
                response = {"error" : true,"message" : "Error fetching data"};
            } else {
            // we got data from Mongo.
            // change it accordingly.
                if(req.body.userEmail !== undefined) {
                    // case where email needs to be updated.
                    data.userEmail = req.body.userEmail;
                }
                if(req.body.userPassword !== undefined) {
                    // case where password needs to be updated
                    data.userPassword = req.body.userPassword;
                }
                // save the data
                data.save(function(err){
                    if(err) {
                        response = {"error" : true,"message" : "Error updating data"};
                    } else {
                        response = {"error" : false,"message" : "Data is updated for "+req.params.id};
                    }
                    res.json(response);
                })
            }
        });
    })
    //DELETE http://localhost:3000/users/id
    //delete data 
    .delete(function(req,res){
        var response = {};
        // find the data
        mongoOp.findById(req.params.id,function(err,data){
            if(err) {
                response = {"error" : true,"message" : "Error fetching data"};
            } else {
                // data exists, remove it.
                mongoOp.remove({_id : req.params.id},function(err){
                    if(err) {
                        response = {"error" : true,"message" : "Error deleting data"};
                    } else {
                        response = {"error" : true,"message" : "Data associated with "+req.params.id+"is deleted"};
                    }
                    res.json(response);
                });
            }
        });
    })


module.exports = router;

mongo.js

var mongoose    =   require("mongoose");
mongoose.connect('mongodb://localhost:27017/lock');
// create instance of Schema
var mongoSchema =   mongoose.Schema;
// create schema
var userSchema  = {
    "userEmail" : String,
    "userPassword" : String
};
// create model if not exists.
module.exports = mongoose.model('userLogin',userSchema);

ViewController.swift This file currently asks for the server IP and allows one to make post Unlock and Lock requests, which I will be adding data to in the future.

I'm wanting to make this view only accessible via logging into to the server as a valid user and being presented with it.

import UIKit

class ViewController: UIViewController {

    func presentAlert() {
        let alertController = UIAlertController(title: "IP?", message: "Please input your unique key:", preferredStyle: .alert)

        let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (_) in
            if let field = alertController.textFields?[0] {
                //this could be lock unique key name etc in future
                UserDefaults.standard.set(field.text, forKey: "userIP")
                UserDefaults.standard.synchronize()
            } else {
                // user did not fill field - doesnt currently work
                print("no input given")
            }
        }

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }


        alertController.addTextField { (textField) in
            textField.placeholder = "IP"
        }

        alertController.addAction(confirmAction)
        alertController.addAction(cancelAction)

        self.present(alertController, animated: true, completion: nil)
    }

    //view did appear for the alert
    override func viewDidAppear(_ animated: Bool) {
        presentAlert()
    }


    override func viewDidLoad() {
        super.viewDidLoad()

    }
    var Timestamp: String {
        return "\(NSDate().timeIntervalSince1970 * 1000)"
    }
    func un_lock()
    {
        let u = UserDefaults.standard.value(forKey: "userIP")!
        let url_to_unlock:String = "http://\(u):3000/unLock"
        print(url_to_unlock)
        let url:URL = URL(string: url_to_unlock)!
        let session = URLSession.shared

        let request = NSMutableURLRequest(url: url)
        request.httpMethod = "POST"
        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData

        //make this work
        let paramString = "data=unLocking at \(Timestamp)"
        request.httpBody = paramString.data(using: String.Encoding.utf8)

        let task = session.dataTask(with: request as URLRequest, completionHandler: {
            (
            data, response, error) in

            guard let _:Data = data, let _:URLResponse = response  , error == nil else {
                print("Error comunicating with server, Check IP")
                return
            }
            //for errors
            let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
            print(dataString! )

        })

        task.resume()
    }

    func lock()
    {

        let u = UserDefaults.standard.value(forKey: "userIP")!
        let url_to_lock:String = "http://\(u):3000/Lock"

        let url:URL = URL(string: url_to_lock)!
        let session = URLSession.shared

        let request = NSMutableURLRequest(url: url)
        request.httpMethod = "POST"
        request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData

        //make this work
        let paramString = "data=Locking at \(Timestamp)"
        request.httpBody = paramString.data(using: String.Encoding.utf8)

        let task = session.dataTask(with: request as URLRequest, completionHandler: {
            (
            data, response, error) in

            guard let _:Data = data, let _:URLResponse = response  , error == nil else {
                print("Error comunicating with server, Check IP")
                return
            }
            //for errors
            let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
            print(dataString! )

        })

        task.resume()

    }

    //button actions 

    @IBAction func Submit(_ sender: UIButton) {

    }

    @IBAction func lock(_ sender: UIButton) {
        lock()
    }

    @IBAction func unLock(_ sender: Any) {
        un_lock()

    }

Show source
| rest   | swift   | ios   | node.js   | mongodb   2017-01-07 18:01 1 Answers

Answers to How to connect to MEAN stack REST api using swift 3 for iOS ( 1 )

  1. 2017-01-08 15:01

    I want to know exactly the same thing. I started with an API tutorial from IFTTT and took a Udemy Node.js course so I started creating the server side first for an iOS app I want to develop.

    I will be following this post and hopefully someone will be kind enough to help us out.

    I did find this tutorial by doing a search so I will be investigating this

    https://www.raywenderlich.com/61264/write-ios-app-uses-node-jsmongodb-web-service

Leave a reply to - How to connect to MEAN stack REST api using swift 3 for iOS

◀ Go back