ERRest in Depth
-
Upload
wo-community -
Category
Technology
-
view
1.091 -
download
2
description
Transcript of ERRest in Depth
![Page 1: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/1.jpg)
MONTREAL JUNE 30, JULY 1ST AND 2ND 2012
MONTREAL JUNE 30, JULY 1ST AND 2ND 2012
ERRest in DepthPascal RobertMacTI.ca
![Page 2: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/2.jpg)
• Request/response loop
• Behavior changes
• Formats
• Transactions
• Same Origin Policy
• Date and time management
The Menu
![Page 3: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/3.jpg)
Request handling
![Page 4: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/4.jpg)
Request
Application.dispatchRequest
ERXRouteRequestHandler(WOActionRequestHandler).handleRequest
YourController(ERXRouteController).performActionNamed
![Page 5: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/5.jpg)
performActionNamed
![Page 6: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/6.jpg)
checkAccess()
• Default implementation in ERXRouteController does nothing
• Override it in your controller for security check
![Page 7: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/7.jpg)
performHtmlActionNamed
• Does <EntityName><ActionName>Page component exists?
• No: fall back to controller
• Yes: Check if component implements IEXRouteComponent
• Yes: return the component
• No: fall back to controller
![Page 8: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/8.jpg)
shouldFailOnMissingHtmlPage
• Does the component was not found or don't implement IEXRouteComponent?
• If shouldFailOnMissingHtmlPage() returns true, call performUnknownAction (will return a 404 NotFound)
• Default is false, override it in your controller if needed.
![Page 9: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/9.jpg)
performRouteActionNamed
• Try to find <actionName>Action method.
• Not found? Try to find <actionName> method.
• Still nothing? Check for annotations.
• Still nothing? Call performUnknownAction
• Got something? Call performActionWithArguments
![Page 10: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/10.jpg)
performUnknownAction
• if (ERXRest.strictMode)
• throw ERXNotAllowedException (HTTP code 405)
• else
• throw FileNotFoundException (HTTP code 404)
![Page 11: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/11.jpg)
performActionWithArguments
• Will invoke the method with the arguments
![Page 12: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/12.jpg)
Objects management
![Page 13: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/13.jpg)
Objects in routes
• /ra/<entityName>/{entity:EntityName}
• routeObjectForKey(key)
• create(filter)
• update(object, filter)
![Page 14: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/14.jpg)
routeObjectForKey
• {<keyName>:<keyType>} in route = keyType result = routeObjectForKey(<keyName>)
• Object is obtained by ERXRestUtils.coerceValueToTypeNamed
![Page 15: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/15.jpg)
coerceValueToTypeNamed
• Where value is transformed to a object or primitive
• If it's an EO or POJO, will use ERXRestClassDescriptionFactory.classDescriptionForEntityName to find the class
• Will call IERXRestDelegate.Factory.delegateForClassDescription().objectOfEntityWithID()
![Page 16: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/16.jpg)
create(filter)
• Will call ERXRestClassDescriptionFactory.classDescriptionForEntityName
• Will call IERXRestDelegate.Factory.delegateForClassDescription().createObjectOfEntityWithID to create a basic EO/POJO
• Will call updateObjectWithFilter()
![Page 17: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/17.jpg)
update(object, filter)
• As with create(filter), will simply call updateObjectWithFilter
![Page 18: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/18.jpg)
updateObjectWithFilter
• Major method
• Will take content from request and update object (PUT request)
• Also used to populate new object (POST request)
![Page 19: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/19.jpg)
Response handling
![Page 20: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/20.jpg)
response(object, filter)
• Will built up the object graph with ERXRestRequestNode.requestNodeWithObjectAndFilter
• Will call response(format, responseNode)
![Page 21: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/21.jpg)
requestNodeWithObjectAndFilter
• If primitive/simple object, will set the value
• If EO/POJO, will call _fillInWithObjectAndFilter
![Page 22: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/22.jpg)
_fillInWithObjectAndFilter
• If object is an array, method take itself
• If not array, will use object's delegate to call primaryKeyForObject, and call _addAttributesAndRelationshipsForObjectOfEntity
![Page 23: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/23.jpg)
response(format, responseNode)
• Returns result of ERXRouteResults(context, restContext, format, responseNode)
• ERXRouteResults.generateResponse() will actually generate the response in requested format
![Page 24: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/24.jpg)
response(ERXRestFetchSpecification, filter)
• Useful to return list of objects ("index" action)
• ERXRestFetchSpecification allow you to set ordering, range, filtering and batching from request
• Will also call response(format, responseNode)
![Page 25: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/25.jpg)
response(int)
• Use that one to send a response without any content in the body
• Check ERXHttpStatusCodes
![Page 26: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/26.jpg)
There's a property for that
![Page 27: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/27.jpg)
"id" key
• ERXRest.idKey : what to use instead of "id"
Default: {"id":2 }
ERRest.idKey=primaryKey {"primaryKey":2 }
![Page 28: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/28.jpg)
"nil" key
• ERXRest.nilKey
To rewrite the "nil" attribute
Default: <someAttribute nil="true"/>
ERXRest.nilKey=cestVide -> <someAttribute cestVide="true"/>
• ERXRest.writeNilKey
Skip the "nil" attribute
Default: <someAttribute nil="true"/>
ERXRest.writeNilKey=false -> <someAttribute nil="true"/>
![Page 29: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/29.jpg)
"type" key
• ERXRest.typeKey
Allow you to change the name of the "type" attribute
Default: {"type":"NameOfEntity"}
ERXRest.typeKey=entityName {"entityName":"NameOfEntity"}
• ERXRest.writeTypeKey
If false, won't write the "type" attribute in the response
ERXRest.writeTypeKey=false -> {id: 2, "type":"NameOfEntity"}
![Page 30: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/30.jpg)
ERXRest.pluralEntityNames
• Default is true
• If set to false, can't use pluralized names
Default: /ra/restEntities
Set to false: /ra/restEntities
![Page 31: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/31.jpg)
ERXRest.suppressTypeAttributesForSimpleTypes
• Only for XML format
• Default value is false
• Default rendering:
<RestEntity primaryKey="1"> <someAttribute type = "integer">2</someAttribute></RestEntity>
• When set to false:
<RestEntity primaryKey="1"> <someAttribute type = "integer">2</someAttribute>
![Page 32: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/32.jpg)
ERXRest.strictMode
• Default is: true
• For missing route, will send 405 (Not Allowed) code, if set to false, will send 404 (Not Found)
• POST requests: will send 201 (Created), if false will send 200 (OK)
![Page 33: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/33.jpg)
ERXRest.routeCase
• ERXRest.routeCase=LowerCamelCase
/ra/restEntities
• ERXRest.routeCase=CamelCase
/ra/RestEntities
• ERXRest.routeCase=LowercaseUnderscore
/ra/rest_entities
![Page 34: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/34.jpg)
ERXRest.parseUnknownExtensions
• /ra/restEntities/3.fsdfsd
• If set to true (the default):
HTTP/1.1 200 Apple WebObjects
Content-Type: text/html
• If set to false:
HTTP/1.0 400 Apple WebObjects
![Page 35: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/35.jpg)
Formats
![Page 36: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/36.jpg)
ERXRest.defaultFormat
• ERXRest.defaultFormat=json|xml|plist|html|...
• Let you specify the default format for all controllers
• Can override it per controller:
protected ERXRestFormat defaultFormat() {
return ERXRestFormat.json(); }
![Page 37: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/37.jpg)
Format detection
• Format detection is in ERXRouteController.format()
• Order of detection
• From extension (.json). Set in ERXRouteRequestHandler.routeForMethodAndPath()
• From the Content-Type header
• Default format (defaultFormat() in controller)
![Page 38: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/38.jpg)
Adding new format
• Your own private format? Use ERXRestFormat.registerFormatNamed()
• Format useful for the commumity? Add them to ERXRestFormat
![Page 39: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/39.jpg)
Same Domain Policy
![Page 40: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/40.jpg)
Same Origin Policy
• Problem: browsers won't load data if client and server not on same domain
• Numerous ways: window.name transport, JSONP and Cross-origin resource sharing (CORS)
• CORS and window.name transport support is part of ERRest
![Page 41: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/41.jpg)
CORS
• Works with Gecko 1.9.1 (Firefox 3.5+), WebKit (Safari 4+, Google Chrome 3+), Opera 12 and IE 8+
• Send extra headers to server
• Client specifiy origin, requested HTTP verb and allowed headers, server returns allowed origin, methods, headers and max-age
![Page 42: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/42.jpg)
CORS preflight
Client request:
OPTIONS /resources/post-here/ HTTP/1.1Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER
Server response:
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER Access-Control-Max-Age: 1728000
Client request:
GET /resources/post-here/ HTTP/1.1Origin: http://foo.example
Server response:
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://foo.example
![Page 43: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/43.jpg)
CORS
• ERXRest.accessControlAllowRequestHeaders
• ERXRest.accessControlAllowRequestMethods
• ERXRest.accessControlMaxAge (default: 1728000)
• ERXRest.accessControlAllowOrigin ('*' to allow all)
![Page 44: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/44.jpg)
window.name Transport
• Dojo use that trick
• Client send ?windowname=true in URL
• Enable it on server with:
ERXRest.allowWindowNameCrossDomainTransport=true
• Will wrap response in HTML code:
<html><script type="text/javascript">window.name='{"id":4,"type":"RestEntity","someAttribute":"commit transaction"}';</script></html>
![Page 45: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/45.jpg)
Status codes
![Page 46: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/46.jpg)
Status code and exceptions
• ObjectNotAvailableException, FileNotFoundException, NoSuchElementException: returns a 404 (Not Found)
• SecurityException: returns a 403 (Forbidden)
• ERXNotAllowedException: returns a 405 (Method Not Allowed)
• ERXValidationException, NSValidation.ValidationException: returns a 400 (Bad Request)
• Anything else: returns a 500 (Internal Server Error)
• Avoid sending 5xx codes if the client made a mistake!
![Page 47: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/47.jpg)
Adding support for new data types
• Add a processor in _ERXJSONConfig
• Add support code in ERXRestUtils
• isPrimitive()
• coerceValueToString()
• coerceValueToTypeNamed
• For dates: add formatter in ERXRestUtils
![Page 48: ERRest in Depth](https://reader034.fdocuments.in/reader034/viewer/2022050906/555a69e0d8b42ae7218b4d86/html5/thumbnails/48.jpg)
Q&A
MONTREAL JUNE 30, JULY 1ST AND 2ND 2012
MONTREAL JUNE 30, JULY 1ST AND 2ND 2012