SlideShare ist ein Scribd-Unternehmen logo
1 von 48
Downloaden Sie, um offline zu lesen
MONTREAL 1/3 JULY 2011




ERRest
Pascal Robert
Conatus/MacTI
The Menu
•   What's new in ERRest        •   Debugging

•   Security                    •   Caching (Sunday!)

•   Versioning                  •   Optimistic locking (Sunday!)

•   HTML routing                •   Using the correct HTTP verbs
                                    and codes (Sunday!)
What's New in ERRest
Anymous updates

•   No need to send the ids of nested objects anymore

•   Call ERXKeyFilter.setAnonymousUpdateEnabled(true)

•   If 1:N relationship, will replace existing values for all nested
    objects
Anonymous update
      protected ERXKeyFilter filter() {
       ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes();
       ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes();
       personFilter.include(Person.FIRST_NAME);

      personFilter.setAnonymousUpdateEnabled(true);

      filter.include(BlogEntry.PERSON, personFilter);
      return filter;
  }

curl -X PUT -d "{ title: 'New Post', person: {firstName: 'Test'} }" http://127.0.0.1/cgi-bin/WebObjects/
SimpleBlog.woa/ra/posts/23.json
Sort ordering on 1:N


•   You can now sort a 1:N relationship

•   Call ERXKeyFilter.setSortOrderings()
Sort ordering
ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes();

ERXKeyFilter categoryFilter = ERXKeyFilter.filterWithAttributes();
categoryFilter.setSortOrderings(BlogCategory.SHORT_NAME.ascs());

filter.include(BlogEntry.CATEGORIES, categoryFilter);
Ignoring unknow keys

•   By default, returns status 500 if unknow attribute is found in
    request

•   To ignore those errors, call:
    yourErxKeyFilter.setUnknownKeyIgnored(true)
ERXRouteController.performActi
         onName


 That method have been split in 5 methods to make it easier to
 override on the method.
ERXRestContext


•   Hold a userInfo dict + the editing context

•   Can pass a different date format per controller

•   Override createRestContext to do that
ERXRestContext
   public class BlogEntryController extends BaseRestController {
...
  @Override
  protected ERXRestContext createRestContext() {
    ERXRestContext restContext = new ERXRestContext(editingContext());
    restContext.setUserInfoForKey("yyyy-MM-dd", "er.rest.dateFormat");
    restContext.setUserInfoForKey("yyyy-MM-dd", "er.rest.timestampFormat");
    return restContext;
  }
}
Other new stuff

•   More strict HTTP status code in responses

•   Support for @QueryParam, @CookieParam and
    @HeaderParam for JSR-311 annotations

•   Indexed bean properties are supported in bean class descriptions

•   updateObjectWithFilter will update subobjects
Security
What other REST services uses?

•   Twitter and Google: OAuth

•   Amazon S3: signature

•   Campaign Monitor: Basic Authentication

•   MailChimp: API Key
Security


•   Basic Authentification

•   Sessions

•   Tokens
USE SSL!
Basic Auth
Basic Auth
•   Pros:

    •   99.9% of HTTP clients can work with it

    •   Easy to implement

•   Cons:

    •   It's just a Base64 representation of your credentials!

    •   No logout option (must close the browser)

    •   No styling of the user/pass box
Implementing Basic Auth
    protected void initAuthentication() throws MemberException, NotAuthorizedException {
    String authValue = request().headerForKey( "authorization" );
    if( authValue != null ) {
      try {
        byte[] authBytes = new BASE64Decoder().decodeBuffer( authValue.replace( "Basic ", "" ) );
        String[] parts = new String( authBytes ).split( ":", 2 );
        String username = parts[0];
        String password = parts[1];
        setAuthenticatedUser(Member.validateLogin(editingContext(), username, password));
      } catch ( IOException e ) {
        log.error( "Could not decode basic auth data: " + e.getMessage() );
        e.printStackTrace();
      }
    } else {
      throw new NotAuthorizedException();
    }
}

public class NotAuthorizedException extends Exception {
  public NotAuthorizedException() {
    super();
  }
}
Implementing Basic Auth
    @Override
public WOActionResults performActionNamed(String actionName, boolean throwExceptions)   {
  // This is if you don't want to use Basic Auth for HTML apps
  if (!(ERXRestFormat.html().name().equals(this.format().name()))) {
    try {
      initAuthentication();
    } catch (UserLoginException ex) {
      WOResponse response = (WOResponse)errorResponse(401);
      response.setHeader("Basic realm="ERBlog"", "WWW-Authenticate");
      return response;
    } catch (NotAuthorizedException ex) {
      WOResponse response = (WOResponse)errorResponse(401);
      response.setHeader("Basic realm="ERBlog"", "WWW-Authenticate");
      return response;
    }
  }
  return super.performActionNamed(actionName, throwExceptions);
}
Sessions
•   Pros:

    •   Can store other data on the server-side (but REST is suppose to be
        stateless)

    •   Easy to implement

•   Cons:

    •   Timeouts...

    •   Sessions are bind to a specific instance of the app

    •   State on the server

    •   Non-browser clients have to store the session ID
Login with a session
     curl -X GET http://127.0.0.1/cgi-bin/WebObjects/App.woa/ra/users/login.json?username=auser&password=md5pass

	    public Session() {
	      setStoresIDsInCookies(true);
	    }

    public WOActionResults loginAction() throws Throwable {
      try {
        String username = request().stringFormValueForKey("username");
        String password = request().stringFormValueForKey("password");
        Member member = Member.validateLogin(session().defaultEditingContext(), username, password);
        return response(member, ERXKeyFilter.filterWithNone());
      } catch (MemberException ex) {
        return errorResponse(401);
      }
    }

(This only works on a version of ERRest after June 9 2011)
Login with a session
protected void initAuthentication() throws MemberException, NotAuthorizedException {
  if (context().hasSession()) {
    Session session = (Session)context()._session();
    if (session.member() == null) {
      throw new NotAuthorizedException();
    }
  } else {
    throw new NotAuthorizedException();
  }
}

@Override
public WOActionResults performActionNamed(String actionName, boolean throwExceptions)   {
  try {
    initAuthentication();
  } catch (MemberException ex) {
    return pageWithName(Login.class);
  } catch (NotAuthorizedException ex) {
    return pageWithName(Login.class);
  }
  return super.performActionNamed(actionName, throwExceptions);
}
Tokens
•   Pros:

    •   No timeout based on inactivity (unless you want to)

•   Cons:

    •   More work involved

    •   Client must request a token

•   Can store the token in a cookie, Authorization header or as a
    query argument
Login with a token
 curl -X GET http://127.0.0.1/cgi-bin/WebObjects/App.woa/ra/members/login.json?username=auser&password=md5pass

public static final ERXBlowfishCrypter crypter = new ERXBlowfishCrypter();

public WOActionResults loginAction() throws Throwable {
  try {
    String username = request().stringFormValueForKey("username");
    String password = request().stringFormValueForKey("password");
    Member member = Member.validateLogin(editingContext(), username, password);
    String hash = crypter.encrypt(member.username());
    if (hash != null) {
      return response(hash, ERXKeyFilter.filterWithAll());
    }
  } catch (MemberException ex) {
    return errorResponse(401);
  }
}
Login with a token
   public static final ERXBlowfishCrypter crypter = new ERXBlowfishCrypter();

protected void initTokenAuthentication() throws MemberException, NotAuthorizedException {
  String tokenValue = this.request().cookieValueForKey("someCookieKeyForToken");
  if (tokenValue != null) {
    String username = crypter.decrypt(tokenValue);
    Member member = Member.fetchMember(editingContext(), Member.USERNAME.eq(username));
    if (member == null) {
      throw new NotAuthorizedException();
    }
  } else {
    throw new NotAuthorizedException();
  }
}

@Override
public WOActionResults performActionNamed(String actionName, boolean throwExceptions)   {
  try {
    initTokenAuthentication();
  } catch (MemberException ex) {
    return pageWithName(Login.class);
  } catch (NotAuthorizedException ex) {
    return pageWithName(Login.class);
  }
  return super.performActionNamed(actionName, throwExceptions);
}
Browser vs System-to-System

  It near impossible to have a REST backend with security that
  works well with both browsers-based and "system-to-system"
  applications.
• For browser apps: use cookies
• For system-to-system: use the Authorization header
Handling HTML and routes auth
    @Override
protected WOActionResults performHtmlActionNamed(String actionName) throws Exception {
  try {
    initCookieAuthentication();
  } catch (MemberException ex) {
    return pageWithName(LoginPage.class);
  } catch (NotAuthorizedException ex) {
    return pageWithName(LoginPage.class);
  }
  return super.performHtmlActionNamed(actionName);
}

@Override
protected WOActionResults performRouteActionNamed(String actionName) throws Exception {
  try {
    initTokenAuthentication();
  } catch (MemberException ex) {
    return errorResponse(401);
  } catch (NotAuthorizedException ex) {
    return errorResponse(401);
  }
  return super.performRouteActionNamed(actionName);
}
Other options

•   OAuth

•   Custom HTTP Authentication scheme

•   Digest Authentification

•   OpenID

•   API Key (similar to token)
Versioning
Versioning

•   Try hard to not having to version your REST services...

•   ... but life is never as planified

•   Use mod_rewrite and ERXApplication._rewriteURL to make it
    easier

    •   Use mod_rewrite even if you are not versionning! It makes
        shorter and nicer URLs
Versioning
In Apache config:

  RewriteEngine On
  RewriteRule ^/your-service/v1/(.*)$ /cgi-bin/WebObjects/YourApp-v1.woa/ra$1 [PT,L]
  RewriteRule ^/your-service/v2/(.*)$ /cgi-bin/WebObjects/YourApp-v2.woa/ra$1 [PT,L]

In Application.java:

  public String _rewriteURL(String url) {
    String processedURL = url;
    if (url != null && _replaceApplicationPathPattern != null && _replaceApplicationPathReplace != null) {
      processedURL = processedURL.replaceFirst(_replaceApplicationPathPattern, _replaceApplicationPathReplace);
    }
    return processedURL;
  }

In the Properties of YourApp-v1.woa:

  er.extensions.ERXApplication.replaceApplicationPath.pattern=/cgi-bin/WebObjects/YourApp-v1.woa/ra
  er.extensions.ERXApplication.replaceApplicationPath.replace=/your-service/v1/

In the Properties of YourApp-v2.woa:

  er.extensions.ERXApplication.replaceApplicationPath.pattern=/cgi-bin/WebObjects/YourApp-v2.woa/ra
  er.extensions.ERXApplication.replaceApplicationPath.replace=/your-service/v2/
Versioning: the gotcha


Watch out for schema changes or other changes that can break
old versions if all versions use the same database schema!
HTML routing
HTML routing?

•   Power of ERRest + WO/EOF + clean URLs!

•   Like DirectActions, but with a lot of work done for you

•   Useful for small public apps that can be cacheable (or accessible
    offline)
Automatic routing: damn easy
•   Create a REST controller for your entity and set
    isAutomaticHtmlRoutingEnabled() to true

•   Create a <EntityName><Action>Page (eg, MemberIndexPage.wo)
    component

•   Register your controller

•   Your component must implements IERXRouteComponent

•   Run your app

•   Profits!
Passing data to the component

Use the ERXRouteParameter annotation to tag methods to
receive data:
@ERXRouteParameter

 public void setMember(Member member) {
   this.member = member;
 }
Automatic HTML routing


If the <EntityName><Action>Page component is not found, it will default
back to the controller and try to execute the requested method.
HTML routing gotchas


•   When submitting forms, you're back to the stateful request
    handler

•   ERXRouteUrlUtils doesn't create rewritten URLs
Manual HTML routing


That's easy: same as a DirectAction:
 public WOActionResults indexAction() throws Throwable {

     return pageWithName(Main.class);
 }
100% REST
public Application() {
    ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler();
    requestHandler.insertRoute(new ERXRoute("Main","", MainController.class, "index"));
...
    setDefaultRequestHandler(requestHandler);
}

public class MainController extends BaseController {

  public MainController(WORequest request) {
    super(request);
  }

  @Override
  protected boolean isAutomaticHtmlRoutingEnabled() {
    return true;
  }

  @Override
  public WOActionResults indexAction() throws Throwable {
    return pageWithName(Main.class);
  }

  @Override
  protected ERXRestFormat defaultFormat() {
    return ERXRestFormat.html();
  }
...
HTML routing: demo
Cool trick: Application Cache
              Manifest
•   Let you specify that some URLs of your app can be available
    offline

•   URLs in the CACHE section will be available offline until you
    change the manifest and remove the URLs from the CACHE
    section

•   Use a DirectAction or a static file to create the manifest

•   One cool reason to use the HTML routing stuff
Cache Manifest
   In your DirectAction class:

  public WOActionResults manifestAction() {
    EOEditingContext ec = ERXEC.newEditingContext();
    WOResponse response = new WOResponse();
    response.appendContentString("CACHE MANIFESTn");
    response.appendContentString("CACHE:n");
    response.appendContentString(ERXRouteUrlUtils.actionUrlForEntityType(this.context(), Entity.ENTITY_NAME, "index",
ERXRestFormat.HTML_KEY, null, false, false) + "n");
    response.appendContentString("NETWORK:n");
    response.setHeader("text/cache-manifest", "Content-Type");
    return response;
  }

In your component:

  <wo:WOGenericContainer elementName="html" manifest=$urlToManifest" lang="en" xmlns="http://www.w3.org/1999/xhtml">

  public String urlForManifest() {
    return this.context().directActionURLForActionNamed("manifest", null);
  }
Debugging
Debugging REST problems
•   curl -v : will display all headers and content, for both request and
    response

•   Firebug and WebKit Inspector : useful to see the
    XMLHttpRequest calls

•   tcpflow : see all trafic on a network interface, can do filters

•   Apache DUMPIO (mod_dumpio) : dump ALL requests and
    responses data to Apache's error log
Debugging Demo
MONTREAL 1/3 JULY 2011




Q&A

Weitere ähnliche Inhalte

Was ist angesagt?

JavaScript
JavaScriptJavaScript
JavaScriptSunil OS
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...GeeksLab Odessa
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDMichele Capra
 
How to write easy-to-test JavaScript
How to write easy-to-test JavaScriptHow to write easy-to-test JavaScript
How to write easy-to-test JavaScriptYnon Perek
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!DataArt
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupHenrik EngstrĂśm
 
Test and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppTest and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppMichele Capra
 
Mastering Oracle ADF Bindings
Mastering Oracle ADF BindingsMastering Oracle ADF Bindings
Mastering Oracle ADF BindingsEuegene Fedorenko
 
Object Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassObject Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassSam Thomas
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackGaryCoady
 
Selenium Webdriver with data driven framework
Selenium Webdriver with data driven frameworkSelenium Webdriver with data driven framework
Selenium Webdriver with data driven frameworkDavid Rajah Selvaraj
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play FrameworkKnoldus Inc.
 
Codegeneration With Xtend
Codegeneration With XtendCodegeneration With Xtend
Codegeneration With XtendSven Efftinge
 
Building High Performance and Reliable Windows Phone 8 Apps
Building High Performance and Reliable Windows Phone 8 AppsBuilding High Performance and Reliable Windows Phone 8 Apps
Building High Performance and Reliable Windows Phone 8 AppsMichele Capra
 
Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるTakahiro Kobaru
 
An introduction to SQLAlchemy
An introduction to SQLAlchemyAn introduction to SQLAlchemy
An introduction to SQLAlchemymengukagan
 
Devoxx 2012 hibernate envers
Devoxx 2012   hibernate enversDevoxx 2012   hibernate envers
Devoxx 2012 hibernate enversRomain Linsolas
 
Intorduction of Playframework
Intorduction of PlayframeworkIntorduction of Playframework
Intorduction of Playframeworkmaltiyadav
 

Was ist angesagt? (20)

JavaScript
JavaScriptJavaScript
JavaScript
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 
How to write easy-to-test JavaScript
How to write easy-to-test JavaScriptHow to write easy-to-test JavaScript
How to write easy-to-test JavaScript
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
Test and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppTest and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 App
 
Mastering Oracle ADF Bindings
Mastering Oracle ADF BindingsMastering Oracle ADF Bindings
Mastering Oracle ADF Bindings
 
Object Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassObject Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypass
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
Selenium Webdriver with data driven framework
Selenium Webdriver with data driven frameworkSelenium Webdriver with data driven framework
Selenium Webdriver with data driven framework
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play Framework
 
Solr workshop
Solr workshopSolr workshop
Solr workshop
 
Codegeneration With Xtend
Codegeneration With XtendCodegeneration With Xtend
Codegeneration With Xtend
 
Building High Performance and Reliable Windows Phone 8 Apps
Building High Performance and Reliable Windows Phone 8 AppsBuilding High Performance and Reliable Windows Phone 8 Apps
Building High Performance and Reliable Windows Phone 8 Apps
 
Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってる
 
An introduction to SQLAlchemy
An introduction to SQLAlchemyAn introduction to SQLAlchemy
An introduction to SQLAlchemy
 
Devoxx 2012 hibernate envers
Devoxx 2012   hibernate enversDevoxx 2012   hibernate envers
Devoxx 2012 hibernate envers
 
119764860 dx-auth
119764860 dx-auth119764860 dx-auth
119764860 dx-auth
 
Intorduction of Playframework
Intorduction of PlayframeworkIntorduction of Playframework
Intorduction of Playframework
 

Ähnlich wie ERRest

Requery overview
Requery overviewRequery overview
Requery overviewSunghyouk Bae
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best PracticesJitendra Zaa
 
Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile appsIvano Malavolta
 
Third Party Auth in WebObjects
Third Party Auth in WebObjectsThird Party Auth in WebObjects
Third Party Auth in WebObjectsWO Community
 
Java EE 8 security and JSON binding API
Java EE 8 security and JSON binding APIJava EE 8 security and JSON binding API
Java EE 8 security and JSON binding APIAlex Theedom
 
Ejb3 Dan Hinojosa
Ejb3 Dan HinojosaEjb3 Dan Hinojosa
Ejb3 Dan HinojosaDan Hinojosa
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
AuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdfAuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdfondrejl1
 
Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's NewTed Pennings
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass SlidesNir Kaufman
 
Teste de Integração com DbUnit e jIntegrity
Teste de Integração com DbUnit e jIntegrityTeste de Integração com DbUnit e jIntegrity
Teste de Integração com DbUnit e jIntegrityWashington Botelho
 
Securing your Pulsar Cluster with Vault_Chris Kellogg
Securing your Pulsar Cluster with Vault_Chris KelloggSecuring your Pulsar Cluster with Vault_Chris Kellogg
Securing your Pulsar Cluster with Vault_Chris KelloggStreamNative
 
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...tdc-globalcode
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with RealmChristian Melchior
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOLCheah Eng Soon
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxcelenarouzie
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web appsIvano Malavolta
 
State management in ASP.NET
State management in ASP.NETState management in ASP.NET
State management in ASP.NETOm Vikram Thapa
 

Ähnlich wie ERRest (20)

Requery overview
Requery overviewRequery overview
Requery overview
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best Practices
 
Local data storage for mobile apps
Local data storage for mobile appsLocal data storage for mobile apps
Local data storage for mobile apps
 
Third Party Auth in WebObjects
Third Party Auth in WebObjectsThird Party Auth in WebObjects
Third Party Auth in WebObjects
 
Wicket 6
Wicket 6Wicket 6
Wicket 6
 
Java EE 8 security and JSON binding API
Java EE 8 security and JSON binding APIJava EE 8 security and JSON binding API
Java EE 8 security and JSON binding API
 
Ejb3 Dan Hinojosa
Ejb3 Dan HinojosaEjb3 Dan Hinojosa
Ejb3 Dan Hinojosa
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
AuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdfAuthN deep.dive—ASP.NET Authentication Internals.pdf
AuthN deep.dive—ASP.NET Authentication Internals.pdf
 
Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's New
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Teste de Integração com DbUnit e jIntegrity
Teste de Integração com DbUnit e jIntegrityTeste de Integração com DbUnit e jIntegrity
Teste de Integração com DbUnit e jIntegrity
 
Securing your Pulsar Cluster with Vault_Chris Kellogg
Securing your Pulsar Cluster with Vault_Chris KelloggSecuring your Pulsar Cluster with Vault_Chris Kellogg
Securing your Pulsar Cluster with Vault_Chris Kellogg
 
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
 
servlets
servletsservlets
servlets
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with Realm
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
 
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docxWeb CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
Web CrawlersrcedusmulylecrawlerController.javaWeb Crawler.docx
 
Local storage in Web apps
Local storage in Web appsLocal storage in Web apps
Local storage in Web apps
 
State management in ASP.NET
State management in ASP.NETState management in ASP.NET
State management in ASP.NET
 

Mehr von WO Community

In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engineWO Community
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsWO Community
 
Build and deployment
Build and deploymentBuild and deployment
Build and deploymentWO Community
 
High availability
High availabilityHigh availability
High availabilityWO Community
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSWO Community
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldWO Community
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful ControllersWO Community
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on WindowsWO Community
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnitWO Community
 
Life outside WO
Life outside WOLife outside WO
Life outside WOWO Community
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache CayenneWO Community
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to WonderWO Community
 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative versionWO Community
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERRESTWO Community
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" patternWO Community
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W WO Community
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languagesWO Community
 

Mehr von WO Community (20)

In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
 
High availability
High availabilityHigh availability
High availability
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWS
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to Wonder
 
iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative version
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W
 
WOver
WOverWOver
WOver
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
 
WOdka
WOdkaWOdka
WOdka
 

KĂźrzlich hochgeladen

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 

KĂźrzlich hochgeladen (20)

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 

ERRest

  • 1. MONTREAL 1/3 JULY 2011 ERRest Pascal Robert Conatus/MacTI
  • 2. The Menu • What's new in ERRest • Debugging • Security • Caching (Sunday!) • Versioning • Optimistic locking (Sunday!) • HTML routing • Using the correct HTTP verbs and codes (Sunday!)
  • 3. What's New in ERRest
  • 4. Anymous updates • No need to send the ids of nested objects anymore • Call ERXKeyFilter.setAnonymousUpdateEnabled(true) • If 1:N relationship, will replace existing values for all nested objects
  • 5. Anonymous update protected ERXKeyFilter filter() { ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes(); ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes(); personFilter.include(Person.FIRST_NAME); personFilter.setAnonymousUpdateEnabled(true); filter.include(BlogEntry.PERSON, personFilter); return filter; } curl -X PUT -d "{ title: 'New Post', person: {firstName: 'Test'} }" http://127.0.0.1/cgi-bin/WebObjects/ SimpleBlog.woa/ra/posts/23.json
  • 6. Sort ordering on 1:N • You can now sort a 1:N relationship • Call ERXKeyFilter.setSortOrderings()
  • 7. Sort ordering ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes(); ERXKeyFilter categoryFilter = ERXKeyFilter.filterWithAttributes(); categoryFilter.setSortOrderings(BlogCategory.SHORT_NAME.ascs()); filter.include(BlogEntry.CATEGORIES, categoryFilter);
  • 8. Ignoring unknow keys • By default, returns status 500 if unknow attribute is found in request • To ignore those errors, call: yourErxKeyFilter.setUnknownKeyIgnored(true)
  • 9. ERXRouteController.performActi onName That method have been split in 5 methods to make it easier to override on the method.
  • 10. ERXRestContext • Hold a userInfo dict + the editing context • Can pass a different date format per controller • Override createRestContext to do that
  • 11. ERXRestContext public class BlogEntryController extends BaseRestController { ... @Override protected ERXRestContext createRestContext() { ERXRestContext restContext = new ERXRestContext(editingContext()); restContext.setUserInfoForKey("yyyy-MM-dd", "er.rest.dateFormat"); restContext.setUserInfoForKey("yyyy-MM-dd", "er.rest.timestampFormat"); return restContext; } }
  • 12. Other new stuff • More strict HTTP status code in responses • Support for @QueryParam, @CookieParam and @HeaderParam for JSR-311 annotations • Indexed bean properties are supported in bean class descriptions • updateObjectWithFilter will update subobjects
  • 14. What other REST services uses? • Twitter and Google: OAuth • Amazon S3: signature • Campaign Monitor: Basic Authentication • MailChimp: API Key
  • 15. Security • Basic Authentication • Sessions • Tokens
  • 18. Basic Auth • Pros: • 99.9% of HTTP clients can work with it • Easy to implement • Cons: • It's just a Base64 representation of your credentials! • No logout option (must close the browser) • No styling of the user/pass box
  • 19. Implementing Basic Auth protected void initAuthentication() throws MemberException, NotAuthorizedException { String authValue = request().headerForKey( "authorization" ); if( authValue != null ) { try { byte[] authBytes = new BASE64Decoder().decodeBuffer( authValue.replace( "Basic ", "" ) ); String[] parts = new String( authBytes ).split( ":", 2 ); String username = parts[0]; String password = parts[1]; setAuthenticatedUser(Member.validateLogin(editingContext(), username, password)); } catch ( IOException e ) { log.error( "Could not decode basic auth data: " + e.getMessage() ); e.printStackTrace(); } } else { throw new NotAuthorizedException(); } } public class NotAuthorizedException extends Exception { public NotAuthorizedException() { super(); } }
  • 20. Implementing Basic Auth @Override public WOActionResults performActionNamed(String actionName, boolean throwExceptions) { // This is if you don't want to use Basic Auth for HTML apps if (!(ERXRestFormat.html().name().equals(this.format().name()))) { try { initAuthentication(); } catch (UserLoginException ex) { WOResponse response = (WOResponse)errorResponse(401); response.setHeader("Basic realm="ERBlog"", "WWW-Authenticate"); return response; } catch (NotAuthorizedException ex) { WOResponse response = (WOResponse)errorResponse(401); response.setHeader("Basic realm="ERBlog"", "WWW-Authenticate"); return response; } } return super.performActionNamed(actionName, throwExceptions); }
  • 21. Sessions • Pros: • Can store other data on the server-side (but REST is suppose to be stateless) • Easy to implement • Cons: • Timeouts... • Sessions are bind to a specic instance of the app • State on the server • Non-browser clients have to store the session ID
  • 22. Login with a session curl -X GET http://127.0.0.1/cgi-bin/WebObjects/App.woa/ra/users/login.json?username=auser&password=md5pass public Session() { setStoresIDsInCookies(true); } public WOActionResults loginAction() throws Throwable { try { String username = request().stringFormValueForKey("username"); String password = request().stringFormValueForKey("password"); Member member = Member.validateLogin(session().defaultEditingContext(), username, password); return response(member, ERXKeyFilter.filterWithNone()); } catch (MemberException ex) { return errorResponse(401); } } (This only works on a version of ERRest after June 9 2011)
  • 23. Login with a session protected void initAuthentication() throws MemberException, NotAuthorizedException { if (context().hasSession()) { Session session = (Session)context()._session(); if (session.member() == null) { throw new NotAuthorizedException(); } } else { throw new NotAuthorizedException(); } } @Override public WOActionResults performActionNamed(String actionName, boolean throwExceptions) { try { initAuthentication(); } catch (MemberException ex) { return pageWithName(Login.class); } catch (NotAuthorizedException ex) { return pageWithName(Login.class); } return super.performActionNamed(actionName, throwExceptions); }
  • 24. Tokens • Pros: • No timeout based on inactivity (unless you want to) • Cons: • More work involved • Client must request a token • Can store the token in a cookie, Authorization header or as a query argument
  • 25. Login with a token curl -X GET http://127.0.0.1/cgi-bin/WebObjects/App.woa/ra/members/login.json?username=auser&password=md5pass public static final ERXBlowfishCrypter crypter = new ERXBlowfishCrypter(); public WOActionResults loginAction() throws Throwable { try { String username = request().stringFormValueForKey("username"); String password = request().stringFormValueForKey("password"); Member member = Member.validateLogin(editingContext(), username, password); String hash = crypter.encrypt(member.username()); if (hash != null) { return response(hash, ERXKeyFilter.filterWithAll()); } } catch (MemberException ex) { return errorResponse(401); } }
  • 26. Login with a token public static final ERXBlowfishCrypter crypter = new ERXBlowfishCrypter(); protected void initTokenAuthentication() throws MemberException, NotAuthorizedException { String tokenValue = this.request().cookieValueForKey("someCookieKeyForToken"); if (tokenValue != null) { String username = crypter.decrypt(tokenValue); Member member = Member.fetchMember(editingContext(), Member.USERNAME.eq(username)); if (member == null) { throw new NotAuthorizedException(); } } else { throw new NotAuthorizedException(); } } @Override public WOActionResults performActionNamed(String actionName, boolean throwExceptions) { try { initTokenAuthentication(); } catch (MemberException ex) { return pageWithName(Login.class); } catch (NotAuthorizedException ex) { return pageWithName(Login.class); } return super.performActionNamed(actionName, throwExceptions); }
  • 27. Browser vs System-to-System It near impossible to have a REST backend with security that works well with both browsers-based and "system-to-system" applications. • For browser apps: use cookies • For system-to-system: use the Authorization header
  • 28. Handling HTML and routes auth @Override protected WOActionResults performHtmlActionNamed(String actionName) throws Exception { try { initCookieAuthentication(); } catch (MemberException ex) { return pageWithName(LoginPage.class); } catch (NotAuthorizedException ex) { return pageWithName(LoginPage.class); } return super.performHtmlActionNamed(actionName); } @Override protected WOActionResults performRouteActionNamed(String actionName) throws Exception { try { initTokenAuthentication(); } catch (MemberException ex) { return errorResponse(401); } catch (NotAuthorizedException ex) { return errorResponse(401); } return super.performRouteActionNamed(actionName); }
  • 29. Other options • OAuth • Custom HTTP Authentication scheme • Digest Authentication • OpenID • API Key (similar to token)
  • 31. Versioning • Try hard to not having to version your REST services... • ... but life is never as planied • Use mod_rewrite and ERXApplication._rewriteURL to make it easier • Use mod_rewrite even if you are not versionning! It makes shorter and nicer URLs
  • 32. Versioning In Apache config: RewriteEngine On RewriteRule ^/your-service/v1/(.*)$ /cgi-bin/WebObjects/YourApp-v1.woa/ra$1 [PT,L] RewriteRule ^/your-service/v2/(.*)$ /cgi-bin/WebObjects/YourApp-v2.woa/ra$1 [PT,L] In Application.java: public String _rewriteURL(String url) { String processedURL = url; if (url != null && _replaceApplicationPathPattern != null && _replaceApplicationPathReplace != null) { processedURL = processedURL.replaceFirst(_replaceApplicationPathPattern, _replaceApplicationPathReplace); } return processedURL; } In the Properties of YourApp-v1.woa: er.extensions.ERXApplication.replaceApplicationPath.pattern=/cgi-bin/WebObjects/YourApp-v1.woa/ra er.extensions.ERXApplication.replaceApplicationPath.replace=/your-service/v1/ In the Properties of YourApp-v2.woa: er.extensions.ERXApplication.replaceApplicationPath.pattern=/cgi-bin/WebObjects/YourApp-v2.woa/ra er.extensions.ERXApplication.replaceApplicationPath.replace=/your-service/v2/
  • 33. Versioning: the gotcha Watch out for schema changes or other changes that can break old versions if all versions use the same database schema!
  • 35. HTML routing? • Power of ERRest + WO/EOF + clean URLs! • Like DirectActions, but with a lot of work done for you • Useful for small public apps that can be cacheable (or accessible offline)
  • 36. Automatic routing: damn easy • Create a REST controller for your entity and set isAutomaticHtmlRoutingEnabled() to true • Create a <EntityName><Action>Page (eg, MemberIndexPage.wo) component • Register your controller • Your component must implements IERXRouteComponent • Run your app • Prots!
  • 37. Passing data to the component Use the ERXRouteParameter annotation to tag methods to receive data: @ERXRouteParameter public void setMember(Member member) { this.member = member; }
  • 38. Automatic HTML routing If the <EntityName><Action>Page component is not found, it will default back to the controller and try to execute the requested method.
  • 39. HTML routing gotchas • When submitting forms, you're back to the stateful request handler • ERXRouteUrlUtils doesn't create rewritten URLs
  • 40. Manual HTML routing That's easy: same as a DirectAction: public WOActionResults indexAction() throws Throwable { return pageWithName(Main.class); }
  • 41. 100% REST public Application() { ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler(); requestHandler.insertRoute(new ERXRoute("Main","", MainController.class, "index")); ... setDefaultRequestHandler(requestHandler); } public class MainController extends BaseController { public MainController(WORequest request) { super(request); } @Override protected boolean isAutomaticHtmlRoutingEnabled() { return true; } @Override public WOActionResults indexAction() throws Throwable { return pageWithName(Main.class); } @Override protected ERXRestFormat defaultFormat() { return ERXRestFormat.html(); } ...
  • 43. Cool trick: Application Cache Manifest • Let you specify that some URLs of your app can be available offline • URLs in the CACHE section will be available offline until you change the manifest and remove the URLs from the CACHE section • Use a DirectAction or a static le to create the manifest • One cool reason to use the HTML routing stuff
  • 44. Cache Manifest In your DirectAction class: public WOActionResults manifestAction() { EOEditingContext ec = ERXEC.newEditingContext(); WOResponse response = new WOResponse(); response.appendContentString("CACHE MANIFESTn"); response.appendContentString("CACHE:n"); response.appendContentString(ERXRouteUrlUtils.actionUrlForEntityType(this.context(), Entity.ENTITY_NAME, "index", ERXRestFormat.HTML_KEY, null, false, false) + "n"); response.appendContentString("NETWORK:n"); response.setHeader("text/cache-manifest", "Content-Type"); return response; } In your component: <wo:WOGenericContainer elementName="html" manifest=$urlToManifest" lang="en" xmlns="http://www.w3.org/1999/xhtml"> public String urlForManifest() { return this.context().directActionURLForActionNamed("manifest", null); }
  • 46. Debugging REST problems • curl -v : will display all headers and content, for both request and response • Firebug and WebKit Inspector : useful to see the XMLHttpRequest calls • tcpflow : see all trac on a network interface, can do lters • Apache DUMPIO (mod_dumpio) : dump ALL requests and responses data to Apache's error log
  • 48. MONTREAL 1/3 JULY 2011 Q&A