Extensible & composable
API
Some context about Nuxeo Platform
- OSGi like component architecture
 - Service oriented Java API
 - Extension point system
 
        
Everything is a plugin
    
Nuxeo API challenges
expose Nuxeo Platform via http without loosing our soul
Being dynamic
- 
Services to expose depends on deployment option
+workflowService +conversionService -relationService - 
Contribute custom Services
+myCustomBusinessService - 
Data Structures (users, docs ...) depends on configuration
{ common : {...}, dublincore : {...}, customSchema : {...}, ... } 
Being composable
- 
"Pack" several services calls inside the same transaction
updateDoc + validateTask + generatePDF - 
Fetch all required information in one call
- aggregate all required info
 
doc attributes + associated tasks + urls 
And also
- 
efficiently manage streams
byte[] ==> evil MultiPart ==> pain - 
manage authentication in an easy and pluggable way
 - 
be HTML/JavaScript friendly
new XMLHttpRequest() 
How we built the Automation API
expose a dynamic http API
JAX-RS vs SOAP
- Soap sucks
- super static / not composable
 - not web friendly (JS, Blob)
 - heavy and complex
 
 - use JAX-RS + JSON
- simple but efficient
 
 
Automation REST EndPoint
- Expose Nuxeo entities as REST resources
- Documents, Users, Workflows, Tasks ...
 
 - 
CRUD via GET, PUT, POST, DELETE
GET /nuxeo/api/v1/path/{path} HTTP/1.1GET /nuxeo/api/v1/id/{uid} HTTP/1.1GET /nuxeo/api/v1/user/{userName} HTTP/1.1GET /nuxeo/api/v1/group/{groupId} HTTP/1.1 
REST Endpoint : GET Document
GET /nuxeo/api/v1/path/default-domain/workspaces/WS/TestNote HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
{
  "entity-type": "document",
  "repository": "default",
  "uid": "6a3998e3-6890-45f5-9c19-b708814a9c1c",
  "path": "/default-domain/workspaces/WS/TestNote",
  "type": "Note",
  "state": "project",
  "versionLabel": "0.0",
  "isCheckedOut": true,
  "title": "TestNote",
  "lastModified": "2014-01-20T13:11:29.64Z",
  ...
}
Automation RPC : Operations EndPoint
- Coarse grained API on top of Java API
- each services can contribute Operations
 
 - Expose endpoint for Operations
- GET to retrieve definition
 - POST to execute
 
 
Operations EndPoint
GET /nuxeo/site/automation/Document.PageProvider HTTP/1.1
HTTP/1.1 200 OK Content-Type: application/json
id":"Document.PageProvider", "label":"PageProvider", "description":"Perform a query ...", "signature":[ "void", "documents" ], "params":[ { "name":"page", "type":"integer", "required":false },{
"name":"query", "type":"string", "required":false, }, ... ] }
Operations EndPoint
POST /nuxeo/site/automation/Document.PageProvider HTTP/1.1
Content-Type: application/json+nxrequest
{ "params" :
    { "query" : "select * from Note",
      "page" : 0
    }
}
HTTP/1.1 200 OK
Content-Type: application/json
{
  "entity-type": "documents",
  "pageIndex": 0,
  "pageSize": 2,
  "pageCount": 2,
  "entries": [
    {
      "entity-type": "document",
      "repository": "default",
      "uid": "3f76a415-ad73-4522-9450-d12af25b7fb4",
      ...
    }, { ...}, ...
 ]
}
Dynamic data structure
Fetch all data in one call
Control Marshaling
- 
use header to control what schemas should be sent
X-NXDocumentProperties dublincore, common, filefetch the data needed on the client side and nothing more
 
GET /nuxeo/api/v1/path/default-domain/workspaces/WS/TestNote HTTP/1.1
X-NXDocumentProperties dublincore, common, file
Control Marshaling
HTTP/1.1 200 OK
Content-Type: application/json
{  "entity-type": "document",
  ...
  "properties": {
    "note:mime_type": "text/x-web-markdown",
    "note:note": "##Hello",
    "files:files": [
      {
        "file": {
          "name": "layout.png",
          "mime-type": "image/png",
          "length": "43627",
          "data": "files/6a3998e3-6890-45f5-9c19-b708814a9c1c"
      } } ] } ...
}
Fetch extra info
- 
use
RestContributorto fetch additional info (Mixins)- urls, breadcrumb info, comments, related documents ...
 
 - 
use header to tell server what info is needed
X-NXContext-Category breadcrumb 
GET /nuxeo/api/v1/path/default-domain/workspaces/WS/TestNote HTTP/1.1
X-NXContext-Category breadcrumb
Fetch REST contributions
HTTP/1.1 200 OK
Content-Type: application/json
{
  "entity-type": "document",
  ...
  "contextParameters": {
    "breadcrumb": {
      "entity-type": "documents",
      "entries": [
        {
          "entity-type": "document",
          "repository": "default",
          "path": "/default-domain",
          ...
        }, ... ] } }
}
Leverage adapter system
- contribute custom logic
 
@WebAdapter(name = BOAdapter.NAME,
            type = "BOService", targetType = "Document")
@Produces({ "application/json+nxentity"})
public class BOAdapter extends DefaultAdapter {
- expose as business object with custom marshaling
 
GET /nuxeo/api/v1/path/domain/workspaces/WS/note@audit HTTP/1.1
GET /nuxeo/api/v1/path/domain/workspaces/WS/note@bo/MyBO HTTP/1.1
Compose API
Expose the API that matches your needs
Automation Chains
- Operations have Input / Output and Arguments
 - Operations can be chained on the service side
- one call , one transaction
 
 
doc => updateDoc
           =(doc)=> validateTask
                            =(doc)=> generatePDF =(Blob)=>
Create new Operations via composition
Compose Chain
via XML / via Drag&Drop
    
Operations and resources
- Bridge Operations and Resources Endpoints
 - "pipe Operation or Chain" on resource
 
 fetch resource => feed Operation or Chain
POST /nuxeo/api/v1/path/domain/workspaces/WS/note/@op/Blob.ToPDF
Operations and Extensions
- Contribute new Operations via Extension Point
 - Contribute new Adapters via Extension Point
 - Compose Operations via Workflow
 
REST EndPoint and Automation

Dynamic and Composable API
Cool, but what is the tradeof
API is more poweful, but more complex
- 
    
Data mapping needs to be dynamic
 - 
Calling dynamic endpoints is more complex than static API
 
endpoint.invoke("createDocument", {input: ... , params:...})
nuxeo.createDocument(path, name, type)
Solution : Provide client lib
- provides some data mapping
 - it does some checks
 - it provides a simpler API 
(createDocument, addComment ...) 
    
Java, Javascript, Python, Dart, Php ...
SOA and Dynamic API
- 
More constraints on ESB UI Designer
- dynamic endpoints and signatures
 
 - 
Needs dynamic data mapping
- introspection is required
 
 - 
Nuxeo complex properties are also a challenge
 
Mule ESB example
- Leverage Java Lib service wrapper
 - Use invoke like pattern for dynamic Operations
- can not dynamicaly build UI from Automation metadata
 
 - Plug Mule DataSense with Nuxeo Types introspection
- Mule fetches datatypes from Nuxeo
 
 
Dynamic data mapping

Next steps
- nuxeo.io !
 - 
Leverage Automation introspection
- generate Service wrapper for client libs
 - generate Blockly fragments for UI Chain designer
 
 
    
Q&A ?
Dynamic and Composable API
By Thierry Delprat
Dynamic and Composable API
- 5,855