Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How a fully scalable SPA with a solid backend is built

the past few weeks I've been hard at work with Angular, Node, TDD, Heroku, Amazon S3 etc. Trying to get a better picture of how a fully scalable SPA with a solid backend is built, working with grunt, bower, haven't dipped my toes in TDD using Jasmine yet, though I understand how the tests are being made through Karma, this is supposedly my next step.

One thing is sure: IT IS A LOT OF INFORMATION


On to the Questions/Rationale on working with all these technologies.

First things first, I played with

  • Angular App https://github.com/angular-app/angular-app
  • NG Boilerplate https://github.com/joshdmiller/ng-boilerplate

and read many dozens of posts etc.

I found NG Boilerplate to be most logical structured (as far as my understanding of these things go).

As a demo project (which evolved from something really small) I want to make a Single Page CRUD Application using:

  • NodeJS as backend
  • Express as a web app framework
  • NG Boilerplate as the Client
  • The app deployed to Heroku
  • MongoDB for DB
  • Amazon S3 for dynamic storage

Now I want to use Angular-Apps's (https://github.com/angular-app/angular-app) server as a backend to my NGBoilerplate kickstarter

I want to know how:

  • from what I see the client connects directly to MongoDB?
  • how does the angular client communicate back and forth to express ?
  • I read an interesting article http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application related to how the authentication works.

Long Story Short, without me asking a ton of questions, could someone please describe in detail the workflow of such an app? Getting the session, login, access to editing the content, tying express routes to angular routes (e.g. X route can be accessed by the admin only) etc. ##

there'a big blur in my head :).

like image 731
Arthur Kovacs Avatar asked Aug 29 '13 19:08

Arthur Kovacs


2 Answers

In the last months I played a lot with these issues and questions and I got to the following conclusion:

For my purposes, I needed an app that relies almost entirely on Angular, without a separate backend, and the present backend should be from Angular.

Why? Because I want all of my eggs in one basket, I don’t want to configure a ton of stuff on a lot of different parts.

As a basis for my project I ended up using ng-boilerplate, as a boilerplate :), with some changes to the development process, Grunt tasks etc, this is for everybody to figure out, depending on each particular project.

Well, the main issue I’m gonna touch here is that, for a true backend, made in Angular, we need secure routes and a secure persistence method, a database.

For the app, I took advantage of the ng-boilerplate's modular and dependency aware structure, I think it’s perfect for a Angular app.

Anyhow, I’m gonna take things top to bottom (final product wise, the build env as I said above, it’s up to you, but ng-boilerplate is awesome), here we go.

  1. On the upper layer we have the actual Angular app, made just the way we want
  2. The server container, is a NodeJS server with express and other modules to take PARTIAL care of the routing on different browsers and devices (In my app, I made HTML5 routing that is augmented by express, .htaccess like settings whenever there’s a partial URL it should redirect to index where Angular will read the path requested and zapp you to that location)
  3. For my case, the whole things runs on Heroku, on a Node.JS application, you can install several other things there if you want to.

Now, for the persistency, to have authentication and security, and NOT to rely on backend for that, I am using firebase (https://www.firebase.com/), there’s some great tutorials there to help you going and have true persistence in your Angular APP, with routes when you are logged in, access to custom tables/objects in DB when you are logged in etc. It’s the real deal.

If you don’t want to rely OAuth’s possible sites to log in with (Facebook, github, persona or twitter) and want custom emails and addresses you can do that directly with Firebase, to create accounts and delete them etc.

FIREBASE Angular Backend.

So, Firebase, just like they say on the site is a powerful API to store and sync data in realtime.

I don’t know exactly how to approach this, so I’m gonna start it with creating a Firebase database. Once we create it, in the backend we have several options, one of which is security.

{
    "rules": {
        ".read": true,
        ".write": "auth != null"
    }
} 

Here, if we read the documentation on https://www.firebase.com/docs/security/security-rules.html we’ll learn that we can add rules for each ‘table' in our database, so we can have like 3 protected ’table’ objects and some that are not protected.

We can protect tables per user basis, per different rules, if logged in or not, we also have inheritance for rules etc, pleas read the documentation there, it really is a good read.

Now, for these rules to take effect we need to enable the Firebase Simple Login and select the desired login method, from Facebook, Twitter, Github, Persona, Email&Password and Anonymous.

For a real app, we need to write info to DB also as anonymous (user sessions etc) and also as logged (with either of the options above) to store and read information.

Me, I wanted to go the quick easy way and made a Facebook authentication, reading the docs there I made a quick Facebook app, and in the settings of the application on Facebook I’m putting Firebase’s backend https://www.dropbox.com/s/xcd4b8tty1nlbm5/Screenshot%202014-01-22%2013.51.26.png

This gives a interim link to login to Facebook and have access to ’tables’ that are otherwise locked if the rule is auth !=null.


NOW, onto the Angular backend.

Firebase provides a library for us to put in our app, and a SimpleLogin lib, also, for Angular, a factory service called AngularFire.

In my case, I made local firebaseService with use methods that connects to my DB:

angular.module('firebaseService', ['firebase'])
  .service('firebaseService', function ($firebase, $rootScope) {

    //Input data in Firebase
    var URL = "https://glowing-fire-xxxx.firebaseio.com";
    var tellFirebase = function(ID, JSON) {
      users = $firebase(new Firebase(URL + '/' + ID));
      users.details = JSON;
      users.$save('details');
    };

    return {
      addUser: function(ID, JSON) {
        tellFirebase(ID, JSON);
        if ($rootScope.debugStatus === true) {
          console.log('Firebase Service .addUSer Called');
        }
      },
      getUser: function(ID) {
        if ($rootScope.debugStatus === true) {
          console.log('Firebase Service .getUser Called');
        }
      }
    };
  }) 

From here we do our READ/WRITE, on the controller’s page I have this:

It’s worth noticing that I have a middleware service (storageManagement) where I switch between Firebase and MongoDB, to avoid confusion.

.controller( 'SomeCtrl', function SomeController( $scope, storageManagement, $firebase, $firebaseSimpleLogin ) { 
     /*===========================
     * ==== FIREBASE LOGIN
     * ===========================*/

    var URL = "https://glowing-fire-XXXXX.firebaseio.com";
    var users = new Firebase(URL);

    $scope.auth = $firebaseSimpleLogin(users, function(error, user){});

    if ($scope.auth.user == null) {
      //$scope.auth.$login('facebook');
    }

    console.log($scope.auth);

    //$scope.auth.$logout('facebook');


    $scope.doLogin = function() {
      console.log($scope.facebookemail);
      console.log($scope.facebookpassword);

      $scope.auth.$login('facebook');

      $scope.$on("$firebaseSimpleLogin:login", function(evt, user) {
        storageManagement.runFirebase();
      });

      /* example of logging in while asking access to permissions like email, user_list, friends_list etc.
       * auth.$login('facebook', {
       rememberMe: true,
       scope: 'email,user_likes'
       });*/
    };
    $scope.doLogout = function() {
      $scope.auth.$logout();
    };
});

I’m adding the $firebase service to my controller, and the $firebaseSimpleLogin one.

This here exposes to scope two buttons, login/logout, that popup the OAuth window from Facebook, with email/password setting you won't need to to go through this I think, for a full understanding please read the full docs at firebase.

SO, once we are logged, we can access tables described in the rules, if we choose email/password, actually even for Facebook or other methods, we can assign certain rules for certain IDENTITIES, so you could have a ADMIN table where you could save settings that get READ on page load to apply whatever you want.

Now, with routes, we can check for the $scope.auth status, if WE PUT IT IN $rootScope, and check for the status when going to a route, if the status checks, we get to that route and it gets populated with stuff from the DB, otherwise, even if someone hacks it’s way to that route it won’t see anything because there are no permissions to read that table for unauthorized/wrong email users.

This is loosely based on this article, http://www.ng-newsletter.com/posts/back-end-with-firebase.html … I had a hard time changing the mindset from what the guy wrote there, but, after ONE WHOLE day, of reading the docs (and setting up middleware, mind you) from Firebase I figured it out, and it works.

The connection to the DB is exposed like one BIG object where you can do whatever operations you want.


This isn't the most complete explanation, but it should get you well on your way to making some awesome things:D

like image 192
Arthur Kovacs Avatar answered Nov 01 '22 16:11

Arthur Kovacs


The best example of this that I've come across is called angular-app.

It's very comprehensive and addresses all your needs. It's written by one of the authors of the fantastic book "Mastering Web Application Development with AngularJS".

https://github.com/angular-app/angular-app

From the github repo:

AngularJS CRUD application demo Purpose

The idea is to demonstrate how to write a typical, non-trivial CRUD application using AngularJS. To showcase AngularJS in its most advantageous environment we've set out to write a simplified project management tool supporting teams using the SCRUM methodology. The sample application tries to show best practices when it comes to: folders structure, using modules, testing, communicating with a REST back-end, organizing navigation, addressing security concerns (authentication / authorization).

We've learned a lot while using and supporting AngularJS on the mailing list and would like to share our experience.

Stack

Persistence store: MongoDB hosted on MongoLab Backend: Node.js Awesome AngularJS on the client CSS based on Twitter's bootstrap Build

It is a complete project with a build system focused on AngularJS apps and tightly integrated with other tools commonly used in the AngularJS community:

powered by Grunt.js test written using Jasmine syntax test are executed by Karma Test Runner (integrated with the Grunt.js build) build supporting JS, CSS and AngularJS templates minification Twitter's bootstrap with LESS templates processing integrated into the build Travis-CI integration

like image 43
davidjnelson Avatar answered Nov 01 '22 16:11

davidjnelson