Webapp
made
simple(r)

No silver bullet™

Reference Webapp

authentication&authorization
validation
business logic
background jobs (reporting, notifications, etc)
HTML generation (formatting dates, numbers, etc)
static resources (JS, CSS, images, etc)

Browser

render HTML page on screen
invoke actions to the remote webapp

Deployment model

web archive (.war) inside servlet container

What happens when...

a static resource has been changed
a Java class has been changed
JVM error (e.g. out of memory)
upgrade servlet container (e.g. security fix)
☠ service interruption ☠

Simplify deploy

minimize service interruptions
separation of concerns
backend vs frontend

Backend

authentication&authorization
validation
business logic
background jobs (reporting, notifications, etc)
HTML generation (formatting dates, numbers, etc)
static resources (JS, CSS, images, etc)

Frontend

HTML templates
static files (JS, CSS, images, etc)
a single page application
maven + webjars
two webapps deployed inside the same servlet container

same-origin policy

frontend www.example.com/frontend/
backend www.example.com/backend/
minimal presentation logic in the backend
independent deploy
one backend, multiple frontends

Frontend without servlet container

leverage the node.js ecosystem
(npm, grunt, gulp, bower, less, uglify, browserify, etc)
build artifact are JS, CSS, images and HTML templates
merge HTML templates with data in the browser
frontend https://frontend.com
backend https://backend.com

Cross Origin Resource Sharing

enable-cors.org
can be hot deployed (no restart needed)
can be served as gzip (for optimal bandwidth usage)
can be served using sendfile syscall (direct streaming file-socket)
less resources used to serve static resources
Race-condition-free deployment

Simplify scaling

high availability
load balancing
sticky sessions on reverse-proxy
e.g. jvmRoute on tomcat
backend restart = session lost
replicate the session
share-nothing architecture

REST

no Sessions
no Cookies
implies that every request must carry on authentication
Authorization: Basic YWRtaW46YWRtaW4=
backends can be restarted freely

Moving the session in the browser

backend: a restful web service
resteasy
maven + JBoss AS
HTTPS
basic auth
JSON + CSV mediatypes
frontend: angularJS
maven + webjars + JBoss AS
// hiding how we store the auth data
app.service('AuthContext', function($localStorage) {
  this.put = function(authentication) {
    localStorage.authentication = authentication;
  };
  this.reset = function() {
    delete $localStorage.authentication;
  };
  this.get = function() {
    return $localStorage.authentication;
  };
  return this;
});
					
// in-memory login/logout

// login
AuthContext.put({ token: basicAuthToken });

// logout
AuthContext.reset();
http interceptors
(similar to servlet filters, spring mvc interceptor, etc)
// put 'Authorization' header on each outgoing request
$httpProvider.interceptors.push(function($rootScope, AuthContext){
  return {
    'request' : function(request) {
       var auth = AuthContext.get();
       if (auth) {
         request.headers.Authorization = auth.token;
       }
       return request;
    }
  }
});
					


  10

					
// postpone session expiry until a 'session.keepalive' event is produced
app.run(function($rootScope, $timeout, AuthContext) {
  var sessionTimeout = moment.duration(10, 'minutes');
  var logout = function() {
    AuthContext.reset();
  };
  var promise = $timeout(logout, sessionTimeout.asMilliseconds());
  $rootScope.$on("session.keepalive", function() {
    $timeout.cancel(promise);
    promise = $timeout(logout, sessionTimeout.asMilliseconds());
  });
});
					
// a 'session.keepalive' event producer
$httpProvider.interceptors.push(function($rootScope) {
  return {
    'request' : function(request) {
      $rootScope.$broadcast("session.keepalive");
      return request;
    }
  };
});
					

Simplify Charting

generating images in the server
resource intensive operation
fetch data from backend
data processing in the frontend
one fetch = multiple charts
charts in Adobe Flash®

HTML5

Chart.js
(canvas, JS, requires IE9+)
d3.js
(SVG, CSS, JS, requires IE9+)
dc.js
C3.js
web workers for intensive data applications
run in a separate, background thread

Simplify Caching

Be explicit about caching
(IE caches everything, even AJAX responses)
Cache-Control: no-cache
Pragma: no-cache
then add cache headers only when proven useful

ETAG

ETAG could be used for optimistic locking
see also @Version annotation of JPA/Hibernate

Simplify pagination

GET /logs?level=ERROR
Link: <logs?level=ERROR&page=2&perPage=10>; rel="next"
Link: <logs?level=ERROR&page=1&perPage=10>; rel="prev"
Link: <logs?level=ERROR&page=3&perPage=10>; rel="next"
Link: <logs?level=ERROR&page=2&perPage=10>; rel="prev"
Link: <logs?level=ERROR&page=4&perPage=10>; rel="next"
Link header introduced by RFC 5988
github pagination

pragmatic restful api

Simplify timestamps

new java.util.Date(1422300695732L);
"Mon Jan 26 20:31:35 CET 2015"
web service provides dates as UNIX timestamps
{ "last_update": 1422300695732 }
new Date(1422300695732);
"Mon Jan 26 2015 20:31:35 GMT+0100"
automatically uses the timezone of the user
alternatively many web services uses ISO-8601
2015-01-26T16:14:49+00:00
moment.js
jodatime:java = momentjs:javascript
back to the past?

END