ERRest In Depth
General architecture
Same Origin policy
Transactions
HTML vs other formats
Response representation
Missing route
Missing object
POJO objects
Headers
Caching
Adding new format
Security
strictMode
Workflow
Query arguments and RXRestFetchSpecification
ERXRestNameRegistry
MapClassDescription / NSDictionaryClassDescription
Calling an action goes like this:
Application.dispatchRequest ->
ERXRouteRequestHandler.handleRequest ->
ERXRouteRequestHandler._handleRequest ->
RestEntitiesController(ERXRouteController).performActionNamed(String actionName, false throwExceptions) ->
RestEntitiesController(ERXRouteController).performRouteActionNamed -> RestEntitiesController(ERXRouteController).performActionWithArguments(Method, Object...) ->
Method.invoke -> ...
RestEntitiesController.indexAction()
performActionNamed:
if (transactionAdaptor.transactionsEnabled() && !transactionAdaptor.isExecutingTransaction(context(), request())) {
if (!transactionAdaptor.willHandleRequest(context(), request())) {
if (transactionAdaptor.didHandleRequest(context(), request())) {
results = stringResponse("Transaction request enqueued.");
} else {
results = stringResponse("Transaction executed.");
}
}
}
if (results == null) {
checkAccess();
}
if (results == null && isAutomaticHtmlRoutingEnabled() && format() == ERXRestFormat.html()) {
results = performHtmlActionNamed(actionName);
}
if (results == null) {
results = performRouteActionNamed(actionName);
}
if (results == null) {
results = response(null, ERXKeyFilter.filterWithAttributes());
}
else if (results instanceof IERXRouteComponent) {
_takeRouteParametersFromRequest(results);
}
ERXRouteController.checkAccess()
Will do nothing by default. Override it to check for security.
protected void checkAccess() throws SecurityException {
}
ERXRouteController.performHtmlActionNamed
protected WOActionResults performHtmlActionNamed(String actionName) throws Exception {
WOActionResults results = null;
String pageName = pageNameForAction(actionName);
if (_NSUtilities.classWithName(pageName) != null) {
try {
results = pageWithName(pageName);
if (!(results instanceof IERXRouteComponent)) {
log.error(pageName + " does not implement IERXRouteComponent, so it will be ignored.");
results = null;
}
}
catch (WOPageNotFoundException e) {
log.info(pageName + " does not exist, falling back to route controller.");
results = null;
}
}
else {
log.info(pageName + " does not exist, falling back to route controller.");
}
if (results == null && shouldFailOnMissingHtmlPage()) {
results = performUnknownAction(actionName);
}
return results;
}
protected String pageNameForAction(String actionName) {
return entityName() + ERXStringUtilities.capitalize(actionName) + "Page";
}
protected boolean shouldFailOnMissingHtmlPage() {
return false;
}
ERXRestUtils
request -> route
/**
* A NameFormat that behaves like Rails -- plural entities, plural routes, lowercase underscore names
* (names_like_this).
*/
public static NameFormat RAILS = new NameFormat(true, true, NameFormat.Case.LowercaseUnderscore);
/**
* A NameFormat that behaves like WO -- singular entities, singular routes, camel names (NamesLikeThis).
*/
public static NameFormat WO = new NameFormat(false, false, NameFormat.Case.CamelCase);
/**
* A NameFormat that behaves like WO -- singular entities, singular routes, lowercase camel names (namesLikeThis).
*/
public static NameFormat WO_LOWER = new NameFormat(false, false, NameFormat.Case.LowerCamelCase);
- ERXRestContext
- contains the editing context and an userInfo dictionnary
- will be populated with er.rest.dateFormat, er.rest.timestampFormatter and er.rest.timestampFormat (read only for non-HTML responses)
- want to change the time format for a specific controller?
- 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;
}you just need to override createRestContext() in your controller if you want to add other stuff to the context (a user, etc.)
- Properties
- ERXRest.idKey (ERXRestFormatDelegate)
- (default "id") Override this property if you want to use a different key for the 'id' attribute** ERXRest.typeKey
- ERXRest.nilKey (ERXRestFormatDelegate)
- ERXRest.writeNilKey (ERXRestFormatDelegate)
- ERXRest.pluralEntityNames (ERXRestFormatDelegate)
- ERXRest.writeTypeKey (ERXRestFormatDelegate)
- ERXRest.suppressTypeAttributesForSimpleTypes (ERXXmlRestWriter)
- (default "false") If set to true, primitive types, like type = "datetime", won't be added to the output
- ERXRest.strictMode
- In ERXMissingRouteController: (default "true") If set to true, status code in the response will be 405 Not Allowed, if set to false, status code will be 404 Not Found
- In ERXRouteController: (default "true") If set to true, status code in the response will be 405 Not Allowed, if set to false, status code will be 404 Not Found
- ERXRouteResults: (default "true") If set to true, creating a ressource will return status code 201 Created, if set to false, will return 200 OK
- ERXRest.pluralEntityNames (ERXRouteRequestHandler)
- ERXRest.routeCase (ERXRouteRequestHandler)
- ERXRest.lowercaseEntityNames (ERXRouteRequestHandler)
- ERXRest.parseUnknownExtensions (ERXRouteRequestHandler)
- (default "true") If set to "false", will return a 404 status code if the format doesn't exist
- ERXRest.missingControllerName (ERXRouteRequestHandler)
- (default "ERXMissingRouteController") Allow you to specify which controller to use when a route doesn't exist
- er.rest.rfcDateFormat
- er.rest.dateFormat
- er.rest.dateFormat.primary
- er.rest.dateFormat.secondary
- er.rest.dateFormatter
- er.rest.timestampFormat
- er.rest.timestampFormat.primary
- er.rest.timestampFormat.secondary
- er.rest.timestampFormatter
- er.rest.rfcDateFormat
- er.rest.jodaTime
- ERXRest.transactionsEnabled (default 'false') ERXRestTransactionRequestAdaptor
- ERXRest.maxEventsPerTransaction (default '50') ERXRestTransactionRequestAdaptor
- ERXRest.accessControlAllowRequestHeaders (ERXRouteController)
- ERXRest.accessControlAllowRequestMethods (ERXRouteController)
- ERXRest.defaultFormat (ERXRouteController)
- (default "xml") Allow you to set the default format for all of your REST controllers
- ERXRest.allowWindowNameCrossDomainTransport (ERXRouteController)
- ERXRest.accessControlMaxAge (ERXRouteController)
- (default 1728000) This header indicates how long the results of a preflight request can be cached. For an example of a preflight request, see the above examples.
- ERXRest.accessControlAllowOrigin (ERXRouteController)
- Set the value to '*' to enable all origins. See https://developer.mozilla.org/En/HTTP_access_control#Access-Control-Allow-Origin
- ERXRest.idKey (ERXRestFormatDelegate)
- JSON Schema
/something?schema=true
public WOActionResults indexAction() {
if (isSchemaRequest()) {
return schemaResponse(showFilter());
}
protected boolean isSchemaRequest() {
return request().stringFormValueForKey("schema") != null;
}
Application(ERXApplication).dispatchRequest(WORequest) line: 2051
ERXRouteRequestHandler(WOActionRequestHandler)._handleRequest(WORequest) line: 221
ERXRouteRequestHandler.getRequestHandlerPathForRequest(WORequest) line: 782
ERXRouteRequestHandler(WOActionRequestHandler)._handleRequest(WORequest) line: 259
PagesController(ERXRouteController).performActionNamed(String) line: 1328
PagesController(ERXRouteController).performActionNamed(String, boolean) line: 1385
PagesController(ERXRouteController).performRouteActionNamed(String) line: 1510
PagesController(ERXRouteController).performActionWithArguments(Method, Object...) line: 1559
...
PagesController.mainPageAction() line: 20
ERXRouteRequestHandler
Properties | |
ERXRest.missingControllerName | (default "ERXMissingRouteController") |
ERXRest.parseUnknownExtensions | ERXRest.parseUnknownExtensions |
ERXRest.pluralEntityNames | ERXRest.pluralEntityNames |
ERXRest.routeCase | ERXRest.routeCase |
ERXRest.lowercaseEntityNames | ERXRest.lowercaseEntityNames |
ERXMissingRouteController is the controller that is used when no route can be found. It's "missing" action is loaded.
Properties | |
ERXRest.strictMode | ERXRest.strictMode |
ERXRouteController