+ All Categories
Home > Technology > MEAN - Notes from the field (Full-Stack Development with Javascript)

MEAN - Notes from the field (Full-Stack Development with Javascript)

Date post: 10-May-2015
Category:
Upload: chris-clarke
View: 764 times
Download: 1 times
Share this document with a friend
Description:
Full-Stack Development with Javascript Angular/Node (AngularJS/NodeJS)
Popular Tags:
79
MEAN - Notes from the field Chris Clarke Hydrahack Birmingham 18th March 2014 Full-Stack Development with Javascript
Transcript
Page 1: MEAN - Notes from the field (Full-Stack Development with Javascript)

MEAN - Notes from the field

Chris ClarkeHydrahack Birmingham18th March 2014

Full-Stack Development with Javascript

Page 2: MEAN - Notes from the field (Full-Stack Development with Javascript)
Page 3: MEAN - Notes from the field (Full-Stack Development with Javascript)
Page 4: MEAN - Notes from the field (Full-Stack Development with Javascript)

• Mongo

• Express

• AngularJS

• NodeJS

http://github.com/linnovate/mean

What’s MEAN?

Page 5: MEAN - Notes from the field (Full-Stack Development with Javascript)

Who are Talis?

Page 6: MEAN - Notes from the field (Full-Stack Development with Javascript)

• MongoDB ~2.5yrs

• Using express/node ~2yrs

• Angular ~9 months

Page 7: MEAN - Notes from the field (Full-Stack Development with Javascript)

Angular AppAngular App

Typical MEAN ShapeDBDB

APIAPI Server side pages

Server side pagesStaticsStatics

JSON

JSONHTMLHTML

JSON

Client side

Server side

Page 8: MEAN - Notes from the field (Full-Stack Development with Javascript)

Typical structure

Page 9: MEAN - Notes from the field (Full-Stack Development with Javascript)

Typical structure

Page 10: MEAN - Notes from the field (Full-Stack Development with Javascript)

Typical structure

Page 11: MEAN - Notes from the field (Full-Stack Development with Javascript)

Typical structure

Page 12: MEAN - Notes from the field (Full-Stack Development with Javascript)

Video Timeline Editor

Page 13: MEAN - Notes from the field (Full-Stack Development with Javascript)

Textbook Player

Page 14: MEAN - Notes from the field (Full-Stack Development with Javascript)

Angular 101

• Single page web app framework, by Google

• Extends HTML vocabulary to provide dynamic views

• Broadly MVC (more accurately MVVM)

• Bi-directional data binding to HTML

Page 15: MEAN - Notes from the field (Full-Stack Development with Javascript)

Angular 101

• Routing

• Templates

• Controllers

• Directives

Page 16: MEAN - Notes from the field (Full-Stack Development with Javascript)

Routing

$routeProvider.when('/modules/:module_id', { templateUrl: 'partials/module.html', controller: 'TeachCtrl', loginRequired: true, activeTab:"teach"});

Page 17: MEAN - Notes from the field (Full-Stack Development with Javascript)

Routing

$routeProvider.when('/modules/:module_id', { templateUrl: 'partials/module.html', controller: 'TeachCtrl', loginRequired: true, activeTab:"teach"});

Page 18: MEAN - Notes from the field (Full-Stack Development with Javascript)

Routing

$routeProvider.when('/modules/:module_id', { templateUrl: 'partials/module.html', controller: 'TeachCtrl', loginRequired: true, activeTab:"teach"});

Page 19: MEAN - Notes from the field (Full-Stack Development with Javascript)

Routing

$routeProvider.when('/modules/:module_id', { templateUrl: 'partials/module.html', controller: 'TeachCtrl', loginRequired: true, activeTab:"teach"});

Page 20: MEAN - Notes from the field (Full-Stack Development with Javascript)

Routing

$routeProvider.when('/modules/:module_id', { templateUrl: 'partials/module.html', controller: 'TeachCtrl', loginRequired: true, activeTab:"teach"});

Page 21: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 22: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 23: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 24: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 25: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 26: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 27: MEAN - Notes from the field (Full-Stack Development with Javascript)

<ul ng-show="modules!=null"> <li ng-repeat="m in modules | orderBy:'title'" ng-class="{active:module._id==m._id}"> <a ng-href="#/modules/{{ m._id }}">{{m.title}}</a> </li> <li> <a ng-click="add()">Add new</a> </li></ul>

Page 28: MEAN - Notes from the field (Full-Stack Development with Javascript)

<input ng-model="profile.first_name" type="text" required><input ng-model="profile.surname" type="text" required><input ng-model="profile.email" type="email" required>

<button ng-disabled="!profile.email" ng-click="update()">Update</button>

Page 29: MEAN - Notes from the field (Full-Stack Development with Javascript)

<input ng-model="profile.first_name" type="text" required><input ng-model="profile.surname" type="text" required><input ng-model="profile.email" type="email" required>

<button ng-disabled="!profile.email" ng-click="update()">Update</button>

Page 30: MEAN - Notes from the field (Full-Stack Development with Javascript)

<input ng-model="profile.first_name" type="text" required><input ng-model="profile.surname" type="text" required><input ng-model="profile.email" type="email" required>

<button ng-disabled="!profile.email" ng-click="update()">Update</button>

Page 31: MEAN - Notes from the field (Full-Stack Development with Javascript)

<input ng-model="profile.first_name" type="text" required><input ng-model="profile.surname" type="text" required><input ng-model="profile.email" type="email" required>

<button ng-disabled="!profile.email" ng-click="update()">Update</button>

Page 32: MEAN - Notes from the field (Full-Stack Development with Javascript)

QuickTime™ and a'avc1' decompressor

are needed to see this picture.

Page 33: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 34: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 35: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 36: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 37: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 38: MEAN - Notes from the field (Full-Stack Development with Javascript)

Controllers Horizontal

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { // update the profile $scope.update = function() { userSvc.updateProfile($scope.profile,function(err,profile) { if (!err) { $scope.profile = profile; } }); }) .controller('SomeOtherCtrl',....);

Page 39: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<textbook-player user="user" textbook="textbook"> ...</textbook-player>

Page 40: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<textbook-player user="user" textbook="textbook"> ...</textbook-player>

Page 41: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<div user="user" textbook="textbook" textbook-player> ...</div>

Page 42: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<div user="user" textbook="textbook" textbook-player> ...</div>

angular.module('talis.directives.player.textbook', []) .directive("textbookPlayer", function() { return { restrict: "A", scope: { user: '=', entity: '=' }, controller: function($scope,textbookSvc) { // textbook logic in here } }});

Page 43: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<div user="user" textbook="textbook" textbook-player> ...</div>

angular.module('talis.directives.player.textbook', []) .directive("textbookPlayer", function() { return { restrict: "A", scope: { user: '=', entity: '=' }, controller: function($scope,textbookSvc) { // textbook logic in here } }});

Page 44: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<div user="user" textbook="textbook" textbook-player> ...</div>

angular.module('talis.directives.player.textbook', []) .directive("textbookPlayer", function() { return { restrict: "A", scope: { user: '=', entity: '=' }, controller: function($scope,textbookSvc) { // textbook logic in here } }});

Page 45: MEAN - Notes from the field (Full-Stack Development with Javascript)

Directives

<div user="user" textbook="textbook" textbook-player> ...</div>

angular.module('talis.directives.player.textbook', []) .directive("textbookPlayer", function() { return { restrict: "A", scope: { user: '=', entity: '=' }, controller: function($scope,textbookSvc) { // textbook logic in here } }});

Page 46: MEAN - Notes from the field (Full-Stack Development with Javascript)

–Jonny Clientside

“Waat?”

Page 47: MEAN - Notes from the field (Full-Stack Development with Javascript)

Notes From the Field

Act I: The Basics

Page 48: MEAN - Notes from the field (Full-Stack Development with Javascript)

Elem vs. Attr directives

<textbook-player user="user" textbook="textbook"> ...</textbook-player>

<div user="user" textbook="textbook" textbook-player> ...</div>

Page 49: MEAN - Notes from the field (Full-Stack Development with Javascript)

Minification

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { .. });

angular.module('talis.controllers.user', []) .controller('AccountCtrl',['$scope','userSvc’, function($scope, userSvc) { ... } ]);

Page 50: MEAN - Notes from the field (Full-Stack Development with Javascript)

Minification

angular.module('talis.controllers.user', []) .controller('AccountCtrl',function($scope, userSvc) { .. });

angular.module('talis.controllers.user', []) .controller('AccountCtrl',['$scope','userSvc’, function($scope, userSvc) { ... } ]);

a.m('talis.controllers.user', []) .c('AccountCtrl',['$scope','userSvc’, function(s, u) { ... } ]);

Page 51: MEAN - Notes from the field (Full-Stack Development with Javascript)

Mongo _id

{ _id: ObjectId(1234), name: “Jonny Clientside”, age: 24, interests: [‘JQuery’,‘HTML5’}

<a ng-href="#/people/{{ p._id }}">{{p.name}}</a>

Page 52: MEAN - Notes from the field (Full-Stack Development with Javascript)

Notes From the Field

Act II: Advanced

Page 53: MEAN - Notes from the field (Full-Stack Development with Javascript)

Angular AppAngular App

Typical MEAN ShapeDBDB

APIAPI Server side pages

Server side pagesStaticsStatics

JSON

JSONHTMLHTML

JSON

Client side

Server side

Page 54: MEAN - Notes from the field (Full-Stack Development with Javascript)

Angular AppAngular App

JSON

9090

9090

9090

9090

Users API

Users API

APIAPI Server side pages

Server side pagesStaticsStatics

JSON

JSON

JSON

Client side

Meta API

Meta API

Files API

Files API

Anno API

Anno API

JSON

DBDBDBDBDBDB DBDB

RedisRedisRedisRedis

HTMLHTML

JSON

Page 55: MEAN - Notes from the field (Full-Stack Development with Javascript)

Logging

• A lot of activity in the client side

• Some within Express/Node server side

• More behind your API proxy

Page 56: MEAN - Notes from the field (Full-Stack Development with Javascript)

var loggingModule = angular.module('talis.services.logging', []);loggingModule.factory( "traceService", function(){ return({ print: printStackTrace }); });loggingModule.provider( "$exceptionHandler",{ $get: function(exceptionLoggingService){ return(exceptionLoggingService); } });

Page 57: MEAN - Notes from the field (Full-Stack Development with Javascript)

var loggingModule = angular.module('talis.services.logging', []);loggingModule.factory( "traceService", function(){ return({ print: printStackTrace }); });loggingModule.provider( "$exceptionHandler",{ $get: function(exceptionLoggingService){ return(exceptionLoggingService); } });

Page 58: MEAN - Notes from the field (Full-Stack Development with Javascript)

loggingModule.factory( "exceptionLoggingService", ["$log","$window", "traceService", function($log, $window, traceService){ function error(exception, cause){

$log.error.apply($log, arguments);

try{ var errorMessage = exception.toString();

var stackTrace = traceService.print({e: exception});

$.ajax({ type: "POST", url: "/logger", contentType: "application/json", data: angular.toJson({ url: $window.location.href, message: errorMessage, type: "exception", stackTrace: stackTrace, cause: ( cause || "") }) }); } catch (loggingError){ $log.warn("Error server-side logging failed"); $log.log(loggingError); } } return(error); }]);

Page 59: MEAN - Notes from the field (Full-Stack Development with Javascript)
Page 60: MEAN - Notes from the field (Full-Stack Development with Javascript)

Logging

Page 61: MEAN - Notes from the field (Full-Stack Development with Javascript)

Security

• APIs secured with OAuth 2.0 Bearer tokens

• Tokens obtained with a key/secret

• If your app is downloaded and run on the client, where do you put the secret?

Page 62: MEAN - Notes from the field (Full-Stack Development with Javascript)

Security

• Have node return the OAuth token as JSON behind a login barrier

• Angular requests this JSON when a route that requires login is first requsted

• If status != 200, Angular app redirects browser to login page

• User logs in, repeat

Page 63: MEAN - Notes from the field (Full-Stack Development with Javascript)

Security

• Dealing with tokens on every service call is a PITA

• Tokens expiring is normal

• Deal with it globally using a couple of advanced $http features

Page 64: MEAN - Notes from the field (Full-Stack Development with Javascript)

.run(function($rootScope,$injector) { $injector.get("$http").defaults.transformRequest = function(data, headersGetter) { headersGetter()['Authorization']="Bearer "+$rootScope.token if (data) { return angular.toJson(data); } };});

Page 65: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope

// now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 66: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope

// now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 67: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope

// now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 68: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope

// now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 69: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope

// now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 70: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope // now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 71: MEAN - Notes from the field (Full-Stack Development with Javascript)

$httpProvider.responseInterceptors.push( function ($rootScope, $q, $injector, $location) { return function(promise) { return promise.then(function(response) { return response; // no action, was successful }, function (response) { // error - was it 401 or something else? if (response.status===401 && response.data.error && response.data.error === "invalid_token") { var deferred = $q.defer(); // defer until we can re-request a new token // Get a new token... (cannot inject $http directly as will cause a circular ref) $injector.get("$http").jsonp('/some/endpoint/that/reissues/tokens?cb=JSON_CALLBACK') .then(function(loginResponse) { if (loginResponse.data) { $rootScope.oauth = loginResponse.data.oauth; // we have a new oauth token - set at $rootScope // now let's retry the original request $injector.get("$http")(response.config).then(function(response) { // we have a successful response - resolve it using deferred deferred.resolve(response); },function(response) { deferred.reject(); // something went wrong }); } else { deferred.reject(); // login.json didn't give us data } }, function(response) { deferred.reject(); // token retry failed, redirect so user can login again $location.path('/user/sign/in'); return; }); return deferred.promise; // return the deferred promise } return $q.reject(response); // not a recoverable error }); }; });

Page 72: MEAN - Notes from the field (Full-Stack Development with Javascript)

Environments

• Pretty usual to deal with prod, dev, testing environment config on the server side

• Inject this into your client side app using a dynamic JS include

Page 73: MEAN - Notes from the field (Full-Stack Development with Javascript)

Environments

<script type="text/javascript" src="env/config.js"></script>

Page 74: MEAN - Notes from the field (Full-Stack Development with Javascript)

Environments

angular.module('talis.environment', [], function($provide) {}). constant('API_ENDPOINT', 'http://localhost:3000'). constant('ACTIVATE_FEATURE_FLIPS',true);

Page 75: MEAN - Notes from the field (Full-Stack Development with Javascript)

Environments

angular.module('talis.environment', [], function($provide) {}). constant('API_ENDPOINT', 'https://talis.com'). constant('ACTIVATE_FEATURE_FLIPS',false);

Page 76: MEAN - Notes from the field (Full-Stack Development with Javascript)

That’s it.

Page 77: MEAN - Notes from the field (Full-Stack Development with Javascript)

http://engineering.talis.com

Page 78: MEAN - Notes from the field (Full-Stack Development with Javascript)

We are hiring!

http://www.talis.com/jobs

Page 79: MEAN - Notes from the field (Full-Stack Development with Javascript)

@talisfacebook.com/talisgroup

+44 (0) 121 374 2740

[email protected]

48 Frederick StreetBirminghamB1 3HN


Recommended