SlideShare a Scribd company logo
1 of 227
+1
                                                       +1
            +1
                       +1
      +1                               +1
                                 +1
 +1              +1                               +1
       +1
                                  +1
                      +1
+1                                               +1
            +1               +1
                                            +1
      +1
                      +1
       +1                   +1
                 +1                    +1
1
Jon Crosby
http://joncrosby.me
Engine Yard Solo
      “The platform for
on-demand management of your
   Ruby on Rails application
        in the cloud.”
We’re Hiring
CloudKit
Open Web
 JSON
Appliance
Open Web
 JSON
Appliance
RESTful Collections
        of
 JSON Documents
CouchDB

Persevere
Ruby
$ gem install cloudkit
WayOfThinking.new
WayOfThinking.web
2009
if (developer.building_web_framework?) {
  MVCAbstraction.new
}
Rails 3
Rails 3 => API
framework = {
  :orm => AR
  :dispatcher => AD}.merge(
    :orm => YourORM)
framework = {
  :orm => AR
  :dispatcher => AD}.merge(
    :orm => YourORM)
framework = {
  :orm => AR
  :dispatcher => AD}.merge(
    :orm => YourORM)
! MVC
! MVC “in the back?”
RESTful Application Architectures
RADAR




Dave Thomas
http://pragdave.pragprog.com/pragdave/2007/03/the_radar_archi.html
Resource Composition in the Browser




                       A.S.
             Focus
Resource Composition in the Browser




                       A.S.
             Focus
Resource Composition in the Browser




                       A.S.
             Focus
Cappuccino




http://280slides.com
Sproutcore




http://sproutcore.com
Desktop / Mobile Apps
ESI

         Caching Layer
                          REST
          Fragment A     Service
Client

                          REST
          Fragment B
                         Service
jQueryUI

 Dojo

MooTools
WayOfThinking.web
Rack
The Web
HTTP
Intermediaries



HTTP
Intermediaries   App



HTTP
Intermediaries   App



HTTP
Intermediaries   Rack



HTTP
HTTP
Intermediaries



HTTP
Middleware



HTTP
Middleware   App



HTTP
Rack is the Web
Constraints
Constraints => Interface
Constraints => Interface => SPEC
CloudKit
REST
Roy Fielding


Architectural Styles and the
Design of Network-based Software Architectures


http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
Build An App
config.ru
require ‘cloudkit’
expose :todos, :profiles
Done
$ rackup config.ru
$ curl -i http://localhost:9292/cloudkit-meta
$ curl -i http://localhost:9292/cloudkit-meta
HTTP/1.1 200 OK
ETag: quot;5b6f484abf2d95cec3ea8867d1754418quot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 33

{quot;urisquot;:[quot;/todosquot;,quot;/profilesquot;]}
$ curl -i -XOPTIONS http://localhost:9292/todos
$ curl -i -XOPTIONS http://localhost:9292/todos
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Allow: GET, HEAD, POST, OPTIONS
$ curl -i http://localhost:9292/todos
$ curl -i http://localhost:9292/todos
HTTP/1.1 200 OK
ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot;
Link: <http://localhost:9292/todos/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 32

{quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
$ curl -i http://localhost:9292/todos
HTTP/1.1 200 OK
ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot;
Link: <http://localhost:9292/todos/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 32

{quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
$ curl -i http://localhost:9292/todos
HTTP/1.1 200 OK
ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot;
Link: <http://localhost:9292/todos/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 32

{quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
$ curl -i http://localhost:9292/todos
HTTP/1.1 200 OK
ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot;
Link: <http://localhost:9292/todos/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 32

{quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
Link Relations and HTTP Header Linking

      IETF Draft by Mark Nottingham



http://tools.ietf.org/html/draft-nottingham-http-link-header-04
Hypermedia
          as the
Engine of Application State
                   -- Fielding
Connectedness
        -- Richardson, Ruby
$ curl -i -XPOST -d'{quot;titlequot;:quot;fooquot;}' 
    http://localhost:9292/todos
$ curl -i -XPOST -d'{quot;titlequot;:quot;fooquot;}' 
http://localhost:9292/todos
HTTP/1.1 201 Created
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 159

{
    quot;okquot;:true,
    quot;uriquot;:quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot;,
    quot;etagquot;:quot;9216dde0-0c7b-012c-af2e-0023dfa0a208quot;,
    quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:13:04 GMTquot;
}
Read-optimized
HTTP-Oriented Storage
Metadata

   +

Document
URI, ETag, Last-Modified, etc.

             +

         Document
SQL
ORM
Tokyo Cabinet
Tokyo Cabinet Tables
todos[“random_id”] = {
  “uri” => “/todos/abc”,
  “etag” => “9216dde0-0c7b-012c”,
  “last_modified” => “Thu, 16 Apr 2009 06:13:04 GMT”,
  “remote_user” => “http://joncrosby.me”,
  “json” => “{”title”:”foo”}”,
  ...
}
Rufus::Tokyo

record = store.query { |q|
  q.add_condition(“uri”, :eql, “/todos/abc”)
}
Schema-free
*
Schema-free
HTTP and JSON
are the Schema
$ curl -i -XPUT -d'{quot;titlequot;:quot;barquot;}' 
 http://localhost:9292/todos/abc
$ curl -i -XPUT -d'{quot;titlequot;:quot;barquot;}' 
http://localhost:9292/todos/abc
HTTP/1.1 201 Created
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 126

{
    quot;okquot;:true,
    quot;uriquot;:quot;/todos/abcquot;,
    quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;,
    quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot;
}
$ curl -i -XOPTIONS http://localhost:9292/todos/abc
$ curl -i -XOPTIONS http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Allow: GET, HEAD, PUT, DELETE, OPTIONS
$ curl -i http://localhost:9292/todos/abc
$ curl -i http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT
ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;
Link: <http://localhost:9292/todos/abc/versions>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 15

{quot;titlequot;:quot;barquot;}
$ curl -i http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT
ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;
Link: <http://localhost:9292/todos/abc/versions>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 15

{quot;titlequot;:quot;barquot;}
$ curl -i http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT
ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;
Link: <http://localhost:9292/todos/abc/versions>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 15

{quot;titlequot;:quot;barquot;}
$ curl -i http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT
ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;
Link: <http://localhost:9292/todos/abc/versions>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 15

{quot;titlequot;:quot;barquot;}
Auto-versioning
/:collection
/:collection/:uuid
/:collection/:uuid/versions
/:collection/:uuid/versions/:etag
/:collection
/:collection/:uuid
/:collection/:uuid/versions
/:collection/:uuid/versions/:etag
/:collection
/:collection/:uuid
/:collection/:uuid/versions
/:collection/:uuid/versions/:etag
/:collection
/:collection/:uuid
/:collection/:uuid/versions
/:collection/:uuid/versions/:etag
/:collection
/:collection/:uuid
/:collection/:uuid/versions
/:collection/:uuid/versions/:etag
$ curl -i http://localhost:9292/todos
$ curl -i http://localhost:9292/todos
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT
ETag: quot;0aca58964aa2e15a9365d72dd4c43472quot;
Link: <http://localhost:9292/todos/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 94

{
    quot;urisquot;:[
       quot;/todos/abcquot;,
       quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot;
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
Lost Update Problem:
Lost Update Problem: Solved
2 Users
2 Users
2 Browsers
2 Users
2 Browsers
1 Document
2 Users
2 Browsers
1 Document

Fight!
2 Users
2 Browsers
1 Document

Hand Wave!
$ curl -i -XPUT -d'{quot;titlequot;:quot;bazquot;}' 
 http://localhost:9292/todos/abc
$ curl -i -XPUT -d'{quot;titlequot;:quot;bazquot;}' 
http://localhost:9292/todos/abc
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 25

{quot;errorquot;:quot;etag requiredquot;}
$ curl -i -XPUT 
-H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' 
-d'{quot;titlequot;:quot;bazquot;}' 
http://localhost:9292/todos/abc
$ curl -i -XPUT 
-H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' 
-d'{quot;titlequot;:quot;bazquot;}' 
http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 126

{
    quot;okquot;:true,
    quot;uriquot;:quot;/todos/abcquot;,
    quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
    quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;
}
$ curl -i -XPUT 
-H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' 
-d'{quot;titlequot;:quot;boxquot;}' 
http://localhost:9292/todos/abc
$ curl -i -XPUT 
-H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' 
-d'{quot;titlequot;:quot;boxquot;}' 
http://localhost:9292/todos/abc
HTTP/1.1 412 Precondition Failed
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 31

{quot;errorquot;:quot;precondition failedquot;}
$ curl -i http://localhost:9292/todos/abc/versions
$ curl -i http://localhost:9292/todos/abc/versions
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;f7aae4894429a39c7c3fe0c8ea9aa00equot;
Link: <http://localhost:9292/todos/abc/versions/_resolved>;
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 109

{
    quot;urisquot;:[
       quot;/todos/abcquot;,
       quot;/todos/abc/versions/f4538ca0-0c7b-012caf2e-0023dfa0a208quot;
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
$ curl -i http://localhost:9292/todos/abc/versions
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;f7aae4894429a39c7c3fe0c8ea9aa00equot;
Link: <http://localhost:9292/todos/abc/versions/_resolved>;
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 109

{
    quot;urisquot;:[
       quot;/todos/abcquot;,
       quot;/todos/abc/versions/f4538ca0-0c7b-012caf2e-0023dfa0a208quot;
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
Why _resolved?
O(n)
1000 documents = 1001 GETs
:-(
Time to rewrite in Scala?
$ curl -i http://localhost:9292/todos/abc/versions/_resolved
$ curl -i http://localhost:9292/todos/abc/versions/_resolved
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;ea2238f8f2da37b70f3d2f09464f166equot;
Link: <http://localhost:9292/todos/abc/versions>; rel=quot;indexquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 384

{
    quot;documentsquot;:[
       {
          quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/abcquot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot;
       },
       {
          quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;barquot;}quot;
       }
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
$ curl -i http://localhost:9292/todos/abc/versions/_resolved
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;ea2238f8f2da37b70f3d2f09464f166equot;
Link: <http://localhost:9292/todos/abc/versions>; rel=quot;indexquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 384

{
    quot;documentsquot;:[
       {
          quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/abcquot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot;
       },
       {
          quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;barquot;}quot;
       }
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
$ curl -i http://localhost:9292/todos/_resolved
$ curl -i http://localhost:9292/todos/_resolved
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;59edaebe03b5fe90fa59ef6de633afcequot;
Link: <http://localhost:9292/todos>; rel=quot;indexquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 369

{
    quot;documentsquot;:[
       {
          quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/abcquot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot;
       },
       {
          quot;etagquot;:quot;9216dde0-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;uriquot;:quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot;,
          quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:13:04 GMTquot;,
          quot;documentquot;:quot;{quot;titlequot;:quot;fooquot;}quot;
     }
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
$ curl -i -XDELETE 
-H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' 
http://localhost:9292/todos/abc
$ curl -i -XDELETE 
-H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' 
http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 92

{
    quot;okquot;:true,
    quot;uriquot;:quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;,
    quot;etagquot;: quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
    quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:33:50 GMTquot;
}
$ curl -i -XDELETE 
-H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' 
http://localhost:9292/todos/abc
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 92

{
    quot;okquot;:true,
    quot;uriquot;:quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;,
    quot;etagquot;: quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;,
    quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:33:50 GMTquot;
}
$ curl -i http://localhost:9292/todos/abc
$ curl -i http://localhost:9292/todos/abc
HTTP/1.1 410 Gone
Link: <http://localhost:9292/todos/abc/versions>;
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot;
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 37

{quot;errorquot;:quot;entity previously deletedquot;}
$ curl -i http://localhost:9292/todos/abc/versions
$ curl -i http://localhost:9292/todos/abc/versions
HTTP/1.1 200 OK
Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT
ETag: quot;22116ccbc80e6356aec956be63c9c440quot;
Link: <http://localhost:9292/todos/abc/versions/_resolved>; 
rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot;
Cache-Control: proxy-revalidate
Content-Type: application/json
Content-Length: 157

{
    quot;urisquot;:[
       quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;,
       quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;
    ],
    quot;totalquot;:2,
    quot;offsetquot;:0
}
Uniform Interface
RESTful Collections
Addressable Nouns
Manipulate with HTTP Methods
Expose Relationships with Links
Fully Discoverable API
What’s Missing?
Ability to Ask Questions
Pagination

/todos?page=2&limit=50
Querying

/todos?user=http://joncrosby.me

       /todos?only=title
Uniform Interface
Uniform Interface

 ... for querying?
JSONQuery
                                 Kris Zyp


http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/
XPath
XPath=> JSONPath
 http://goessner.net/articles/JsonPath/
Array Slice Operators


    /todos[10:20]
Array Slice Operators


   /todos[10:20:2]
Comparisons


/todos[?priority>=3]
Chained Expressions


/todos[?priority>=3][0:5]
Extractions


/todos[=name]
Sorting


/todos[/priority][name]
Recursive Finders


/todos[objectid..firstName]
Unions


/todos[?foo=‘bar’,rating=4]
JSONQuery.js
http://github.com/jcrosby/jsonquery
jquery.cloudkit.js
http://github.com/jcrosby/jquery-cloudkit
var store = $.cloudkit;
store.boot({
  success: function() {
     // do something
  },
  error: function(status) {
     // fail gracefully
  }
});
var store = $.cloudkit;
store.boot({
  success: function() {
     // do something
  },
  error: function(status) {
     // fail gracefully
  }
});
var store = $.cloudkit;
store.boot({
  success: function() {
     // do something
  },
  error: function(status) {
     // fail gracefully
  }
});
store.boot
1) Local collection per remote collection
2) Loads remote data
store.boot
1) Local collection per remote collection
2) Loads remote data
store.boot
1) Local collection per remote collection
2) Loads remote data
var store = $.cloudkit;
store.boot({
  success: function() {
     // do something
  },
  error: function(status) {
     // fail gracefully
  }
});
var store = $.cloudkit;
store.boot({
  success: function() {
     // do something
  },
  error: function(status) {
     // fail gracefully
  }
});
// insert a 'todo'
store.collection('todos').create({name:quot;fooquot;}, {
   success: function(todo) {
     // do something with the todo
     alert(todo.json().name);
   }
});
// insert a 'todo'
store.collection('todos').create({name:quot;fooquot;}, {
   success: function(todo) {
     // do something with the todo
     alert(todo.json().name);
   }
});
// insert a 'todo'
store.collection('todos').create({name:quot;fooquot;}, {
   success: function(todo) {
     // do something with the todo
     alert(todo.json().name);
   }
});
// insert a 'todo'
store.collection('todos').create({name:quot;fooquot;}, {
   success: function(todo) {
     // do something with the todo
     alert(todo.json().name);
   }
});
// insert a 'todo'
store.collection('todos').create({name:quot;fooquot;}, {
   success: function(todo) {
     // do something with the todo
     alert(todo.json().name);
   }
});
// update the 'todo'
todo.update({name:quot;barquot;} {
  success: function() {
     // updated remotely, ready for use
     alert(todo.json().name); // now “bar”
  },
  error: function(status) {
     // fail gracefully or recover
  }
});
// update the 'todo'
todo.update({name:quot;barquot;} {
  success: function() {
     // updated remotely, ready for use
     alert(todo.json().name); // now “bar”
  },
  error: function(status) {
     // fail gracefully or recover
  }
});
// update the 'todo'
todo.update({name:quot;barquot;} {
  success: function() {
     // updated remotely, ready for use
     alert(todo.json().name); // now “bar”
  },
  error: function(status) {
     // fail gracefully or recover
  }
});
// update the 'todo'
todo.update({name:quot;barquot;} {
  success: function() {
     // updated remotely, ready for use
     alert(todo.json().name); // now “bar”
  },
  error: function(status) {
     // fail gracefully or recover
  }
});
// update the 'todo'
todo.update({name:quot;barquot;} {
  success: function() {
     // updated remotely, ready for use
     alert(todo.json().name); // now “bar”
  },
  error: function(status) {
     // fail gracefully or recover
  }
});
Recovery
410 => Remove Locally? Create New?
Recovery
410 => Remove Locally? Create New?
412 => Progressive Diff/Merge
Recovery
410 => Remove Locally? Create New?
412 => Progressive Diff/Merge (Sync)
// delete the 'todo'
todo.destroy({
  success: function() {
    // the 'todo' has now been deleted
  }
});
// delete the 'todo'
todo.destroy({
  success: function() {
    // the 'todo' has now been deleted
  }
});
// delete the 'todo'
todo.destroy({
  success: function() {
    // the 'todo' has now been deleted
  }
});
// delete the 'todo'
todo.destroy({
  success: function() {
    // the 'todo' has now been deleted
  }
});
store.collection('todos').query(quot;?name='foo'quot;);
Johnson

        Ruby/JavaScript Bridge



http://github.com/jbarnette/johnson
1.0 Roadmap
JSONSchema

        /:collection/_schema


http://www.json.com/json-schema-proposal/
{
    quot;descriptionquot;:quot;A personquot;,
    quot;typequot;:quot;objectquot;,
    quot;propertiesquot;: {
      quot;namequot;: {
         quot;typequot;:quot;stringquot;
      },
      quot;agequot;: {
         quot;typequot;:quot;integerquot;,
         quot;maximumquot;:125
      }
    }
}
Open Web
 JSON
Appliance
Open Web
 JSON
Appliance
require ‘cloudkit’
expose :todos, :profiles
require ‘cloudkit’
contain :todos, :profiles
OpenID
      +
    OAuth
      +
OAuth/Discovery
Browser


OAuth    OpenID   Service
Browser


OAuth    OpenID   Service
Browser


        {...}
OAuth            OpenID   Service
Browser


OAuth    OpenID   Service
Browser


OAuth    OpenID   Service

          {...}

          Login
Browser


OAuth    OpenID   Service
Browser


OAuth    OpenID   Service
Browser


OAuth    OpenID   Service
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


        {...}
OAuth           OpenID   Service
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


OAuth     OpenID     Service

           {...}

           Login
curl -i http://localhost:9292/todos
HTTP/1.1 401 Unauthorized
Connection: close
Date: Thu, 15 Jan 2009 22:24:23 GMT
WWW-Authenticate: OAuth realm=quot;http://localhost:9292quot;
Link: <http://localhost:9292/oauth/meta>;
rel=quot;http://oauth.net/discovery/1.0/rel/providerquot;
Content-Type: text/html
Set-Cookie: rack.session=d6b1c6aa6d463a478eb9af0e921eb997;
path=/; HttpOnly
Content-Length: 1280

<!DOCTYPE html PUBLIC quot;-//W3C//DTD XHTML 1.0 Transitional//ENquot;
   quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtdquot;>
<html xmlns=quot;http://www.w3.org/1999/xhtmlquot; xml:lang=quot;enquot; lang=quot;enquot;>
... etc ...
$ curl -i http://localhost:9292/oauth/meta
$ curl -i http://localhost:9292/oauth/meta

<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<XRD>
 <Type>http://oauth.net/discovery/1.0</Type>
 <Service>
  <Type>http://oauth.net/discovery/1.0/rel/provider</Type>
  <URI>http://localhost:9292/oauth</URI>
 </Service>
</XRD>
$ curl -i http://localhost:9292/oauth
(squint)
<?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?>
<XRDS xmlns=quot;xri://$xrdsquot;>
 <XRD xml:id=quot;oauthquot; xmlns:simple=quot;http://xrds-simple.net/core/1.0quot; xmlns=quot;xri://$XRD*($v*2.0)quot; version=quot;2.0quot;>
  <Type>xri://$xrds*simple</Type>
  <Expires>2009-02-14T22:27:50Z</Expires>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/core/1.0/endpoint/request</Type>
   <Type>http://oauth.net/core/1.0/parameters/auth-header</Type>
   <Type>http://oauth.net/core/1.0/parameters/uri-query</Type>
   <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type>
   <URI>http://localhost:9292/oauth/request_tokens</URI>
  </Service>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/core/1.0/endpoint/authorize</Type>
   <Type>http://oauth.net/core/1.0/parameters/uri-query</Type>
   <URI>http://localhost:9292/oauth/authorization</URI>
  </Service>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/core/1.0/endpoint/access</Type>
   <Type>http://oauth.net/core/1.0/parameters/auth-header</Type>
   <Type>http://oauth.net/core/1.0/parameters/uri-query</Type>
   <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type>
   <URI>http://localhost:9292/oauth/access_tokens</URI>
  </Service>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/core/1.0/endpoint/resource</Type>
   <Type>http://oauth.net/core/1.0/parameters/auth-header</Type>
   <Type>http://oauth.net/core/1.0/parameters/uri-query</Type>
   <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type>
  </Service>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/discovery/1.0/consumer-identity/static</Type>
   <LocalID>cloudkitconsumer</LocalID>
  </Service>
 </XRD>
 <XRD xmlns=quot;xri://$XRD*($v*2.0)quot; version=quot;2.0quot;>
  <Type>xri://$xrds*simple</Type>
  <Service priority=quot;10quot;>
   <Type>http://oauth.net/discovery/1.0</Type>
   <URI>#oauth</URI>
  </Service>
 </XRD>
</XRDS>
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


OAuth     OpenID     Service
Service or Desktop App


OAuth     OpenID     Service
1.0
JSONQuery Release
JSONSchema Release
Templating
Done
CloudKit
http://getcloudkit.com
 http://joncrosby.me

More Related Content

Similar to CloudKit

Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)
True-Vision
 
Socket applications
Socket applicationsSocket applications
Socket applications
João Moura
 
cdac@parag.gajbhiye@test123
cdac@parag.gajbhiye@test123cdac@parag.gajbhiye@test123
cdac@parag.gajbhiye@test123
Parag Gajbhiye
 
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
Ilya Grigorik
 

Similar to CloudKit (20)

Service Oriented Integration With ServiceMix
Service Oriented Integration With ServiceMixService Oriented Integration With ServiceMix
Service Oriented Integration With ServiceMix
 
Velocity EU 2012 - Third party scripts and you
Velocity EU 2012 - Third party scripts and youVelocity EU 2012 - Third party scripts and you
Velocity EU 2012 - Third party scripts and you
 
Consegi 2010 - Dicas de Desenvolvimento Web com Ruby
Consegi 2010 - Dicas de Desenvolvimento Web com RubyConsegi 2010 - Dicas de Desenvolvimento Web com Ruby
Consegi 2010 - Dicas de Desenvolvimento Web com Ruby
 
Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)Rails Presentation (Anton Dmitriyev)
Rails Presentation (Anton Dmitriyev)
 
Stefan Judis "Did we(b development) lose the right direction?"
Stefan Judis "Did we(b development) lose the right direction?"Stefan Judis "Did we(b development) lose the right direction?"
Stefan Judis "Did we(b development) lose the right direction?"
 
Celix universal OSGi
Celix universal OSGiCelix universal OSGi
Celix universal OSGi
 
JSON Viewer XPATH Workbook
JSON Viewer XPATH WorkbookJSON Viewer XPATH Workbook
JSON Viewer XPATH Workbook
 
Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
 
Teflon - Anti Stick for the browser attack surface
Teflon - Anti Stick for the browser attack surfaceTeflon - Anti Stick for the browser attack surface
Teflon - Anti Stick for the browser attack surface
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
More Secrets of JavaScript Libraries
More Secrets of JavaScript LibrariesMore Secrets of JavaScript Libraries
More Secrets of JavaScript Libraries
 
cdac@parag.gajbhiye@test123
cdac@parag.gajbhiye@test123cdac@parag.gajbhiye@test123
cdac@parag.gajbhiye@test123
 
Beyond the Node: Arkestration with Noah
Beyond the Node: Arkestration with NoahBeyond the Node: Arkestration with Noah
Beyond the Node: Arkestration with Noah
 
Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)Application Security for Rich Internet Applicationss (Jfokus 2012)
Application Security for Rich Internet Applicationss (Jfokus 2012)
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
Zero to Sixty: AWS Elastic Beanstalk (DMG204) | AWS re:Invent 2013
Zero to Sixty: AWS Elastic Beanstalk (DMG204) | AWS re:Invent 2013Zero to Sixty: AWS Elastic Beanstalk (DMG204) | AWS re:Invent 2013
Zero to Sixty: AWS Elastic Beanstalk (DMG204) | AWS re:Invent 2013
 
Mobile web-debug
Mobile web-debugMobile web-debug
Mobile web-debug
 
0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services0-60 with Goliath: Building High Performance Ruby Web-Services
0-60 with Goliath: Building High Performance Ruby Web-Services
 
Enabling Microservices @Orbitz - Velocity Conf 2015
Enabling Microservices @Orbitz - Velocity Conf 2015Enabling Microservices @Orbitz - Velocity Conf 2015
Enabling Microservices @Orbitz - Velocity Conf 2015
 
Web Application Defences
Web Application DefencesWeb Application Defences
Web Application Defences
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Recently uploaded (20)

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 

CloudKit

  • 1. +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 1
  • 3.
  • 4. Engine Yard Solo “The platform for on-demand management of your Ruby on Rails application in the cloud.”
  • 9. RESTful Collections of JSON Documents
  • 11. Ruby
  • 12. $ gem install cloudkit
  • 15. 2009
  • 18. Rails 3 => API
  • 19. framework = { :orm => AR :dispatcher => AD}.merge( :orm => YourORM)
  • 20. framework = { :orm => AR :dispatcher => AD}.merge( :orm => YourORM)
  • 21. framework = { :orm => AR :dispatcher => AD}.merge( :orm => YourORM)
  • 22. ! MVC
  • 23. ! MVC “in the back?”
  • 26. Resource Composition in the Browser A.S. Focus
  • 27. Resource Composition in the Browser A.S. Focus
  • 28. Resource Composition in the Browser A.S. Focus
  • 32. ESI Caching Layer REST Fragment A Service Client REST Fragment B Service
  • 35. Rack
  • 37.
  • 38. HTTP
  • 40. Intermediaries App HTTP
  • 41. Intermediaries App HTTP
  • 42. Intermediaries Rack HTTP
  • 43.
  • 44. HTTP
  • 47. Middleware App HTTP
  • 48. Rack is the Web
  • 53. REST
  • 54. Roy Fielding Architectural Styles and the Design of Network-based Software Architectures http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  • 58. Done
  • 60. $ curl -i http://localhost:9292/cloudkit-meta
  • 61. $ curl -i http://localhost:9292/cloudkit-meta HTTP/1.1 200 OK ETag: quot;5b6f484abf2d95cec3ea8867d1754418quot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 33 {quot;urisquot;:[quot;/todosquot;,quot;/profilesquot;]}
  • 62. $ curl -i -XOPTIONS http://localhost:9292/todos
  • 63. $ curl -i -XOPTIONS http://localhost:9292/todos HTTP/1.1 200 OK Content-Type: application/json Content-Length: 0 Allow: GET, HEAD, POST, OPTIONS
  • 64. $ curl -i http://localhost:9292/todos
  • 65. $ curl -i http://localhost:9292/todos HTTP/1.1 200 OK ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot; Link: <http://localhost:9292/todos/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 32 {quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
  • 66. $ curl -i http://localhost:9292/todos HTTP/1.1 200 OK ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot; Link: <http://localhost:9292/todos/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 32 {quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
  • 67. $ curl -i http://localhost:9292/todos HTTP/1.1 200 OK ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot; Link: <http://localhost:9292/todos/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 32 {quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
  • 68. $ curl -i http://localhost:9292/todos HTTP/1.1 200 OK ETag: quot;df392c5664e6ecd64b83210fb925f6c8quot; Link: <http://localhost:9292/todos/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 32 {quot;urisquot;:[],quot;totalquot;:0,quot;offsetquot;:0}
  • 69. Link Relations and HTTP Header Linking IETF Draft by Mark Nottingham http://tools.ietf.org/html/draft-nottingham-http-link-header-04
  • 70. Hypermedia as the Engine of Application State -- Fielding
  • 71. Connectedness -- Richardson, Ruby
  • 72. $ curl -i -XPOST -d'{quot;titlequot;:quot;fooquot;}' http://localhost:9292/todos
  • 73. $ curl -i -XPOST -d'{quot;titlequot;:quot;fooquot;}' http://localhost:9292/todos HTTP/1.1 201 Created Cache-Control: no-cache Content-Type: application/json Content-Length: 159 { quot;okquot;:true, quot;uriquot;:quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot;, quot;etagquot;:quot;9216dde0-0c7b-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:13:04 GMTquot; }
  • 76. Metadata + Document
  • 77. URI, ETag, Last-Modified, etc. + Document
  • 78. SQL
  • 79. ORM
  • 82. todos[“random_id”] = { “uri” => “/todos/abc”, “etag” => “9216dde0-0c7b-012c”, “last_modified” => “Thu, 16 Apr 2009 06:13:04 GMT”, “remote_user” => “http://joncrosby.me”, “json” => “{”title”:”foo”}”, ... }
  • 83. Rufus::Tokyo record = store.query { |q| q.add_condition(“uri”, :eql, “/todos/abc”) }
  • 86. HTTP and JSON are the Schema
  • 87. $ curl -i -XPUT -d'{quot;titlequot;:quot;barquot;}' http://localhost:9292/todos/abc
  • 88. $ curl -i -XPUT -d'{quot;titlequot;:quot;barquot;}' http://localhost:9292/todos/abc HTTP/1.1 201 Created Cache-Control: no-cache Content-Type: application/json Content-Length: 126 { quot;okquot;:true, quot;uriquot;:quot;/todos/abcquot;, quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot; }
  • 89. $ curl -i -XOPTIONS http://localhost:9292/todos/abc
  • 90. $ curl -i -XOPTIONS http://localhost:9292/todos/abc HTTP/1.1 200 OK Content-Type: application/json Content-Length: 0 Allow: GET, HEAD, PUT, DELETE, OPTIONS
  • 91. $ curl -i http://localhost:9292/todos/abc
  • 92. $ curl -i http://localhost:9292/todos/abc HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 15 {quot;titlequot;:quot;barquot;}
  • 93. $ curl -i http://localhost:9292/todos/abc HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 15 {quot;titlequot;:quot;barquot;}
  • 94. $ curl -i http://localhost:9292/todos/abc HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 15 {quot;titlequot;:quot;barquot;}
  • 95. $ curl -i http://localhost:9292/todos/abc HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT ETag: quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 15 {quot;titlequot;:quot;barquot;}
  • 102. $ curl -i http://localhost:9292/todos
  • 103. $ curl -i http://localhost:9292/todos HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:15:49 GMT ETag: quot;0aca58964aa2e15a9365d72dd4c43472quot; Link: <http://localhost:9292/todos/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 94 { quot;urisquot;:[ quot;/todos/abcquot;, quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot; ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 108. 2 Users 2 Browsers 1 Document
  • 109. 2 Users 2 Browsers 1 Document Fight!
  • 110. 2 Users 2 Browsers 1 Document Hand Wave!
  • 111. $ curl -i -XPUT -d'{quot;titlequot;:quot;bazquot;}' http://localhost:9292/todos/abc
  • 112. $ curl -i -XPUT -d'{quot;titlequot;:quot;bazquot;}' http://localhost:9292/todos/abc HTTP/1.1 400 Bad Request Cache-Control: no-cache Content-Type: application/json Content-Length: 25 {quot;errorquot;:quot;etag requiredquot;}
  • 113. $ curl -i -XPUT -H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' -d'{quot;titlequot;:quot;bazquot;}' http://localhost:9292/todos/abc
  • 114. $ curl -i -XPUT -H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' -d'{quot;titlequot;:quot;bazquot;}' http://localhost:9292/todos/abc HTTP/1.1 200 OK Cache-Control: no-cache Content-Type: application/json Content-Length: 126 { quot;okquot;:true, quot;uriquot;:quot;/todos/abcquot;, quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot; }
  • 115. $ curl -i -XPUT -H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' -d'{quot;titlequot;:quot;boxquot;}' http://localhost:9292/todos/abc
  • 116. $ curl -i -XPUT -H'If-Match:f4538ca0-0c7b-012c-af2e-0023dfa0a208' -d'{quot;titlequot;:quot;boxquot;}' http://localhost:9292/todos/abc HTTP/1.1 412 Precondition Failed Cache-Control: no-cache Content-Type: application/json Content-Length: 31 {quot;errorquot;:quot;precondition failedquot;}
  • 117. $ curl -i http://localhost:9292/todos/abc/versions
  • 118. $ curl -i http://localhost:9292/todos/abc/versions HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;f7aae4894429a39c7c3fe0c8ea9aa00equot; Link: <http://localhost:9292/todos/abc/versions/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 109 { quot;urisquot;:[ quot;/todos/abcquot;, quot;/todos/abc/versions/f4538ca0-0c7b-012caf2e-0023dfa0a208quot; ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 119. $ curl -i http://localhost:9292/todos/abc/versions HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;f7aae4894429a39c7c3fe0c8ea9aa00equot; Link: <http://localhost:9292/todos/abc/versions/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 109 { quot;urisquot;:[ quot;/todos/abcquot;, quot;/todos/abc/versions/f4538ca0-0c7b-012caf2e-0023dfa0a208quot; ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 121. O(n)
  • 122. 1000 documents = 1001 GETs
  • 123. :-(
  • 124. Time to rewrite in Scala?
  • 125. $ curl -i http://localhost:9292/todos/abc/versions/_resolved
  • 126. $ curl -i http://localhost:9292/todos/abc/versions/_resolved HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;ea2238f8f2da37b70f3d2f09464f166equot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;indexquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 384 { quot;documentsquot;:[ { quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/abcquot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot; }, { quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;barquot;}quot; } ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 127. $ curl -i http://localhost:9292/todos/abc/versions/_resolved HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;ea2238f8f2da37b70f3d2f09464f166equot; Link: <http://localhost:9292/todos/abc/versions>; rel=quot;indexquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 384 { quot;documentsquot;:[ { quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/abcquot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot; }, { quot;etagquot;:quot;f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:15:49 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;barquot;}quot; } ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 128. $ curl -i http://localhost:9292/todos/_resolved
  • 129. $ curl -i http://localhost:9292/todos/_resolved HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;59edaebe03b5fe90fa59ef6de633afcequot; Link: <http://localhost:9292/todos>; rel=quot;indexquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 369 { quot;documentsquot;:[ { quot;etagquot;:quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/abcquot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:25:41 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;bazquot;}quot; }, { quot;etagquot;:quot;9216dde0-0c7b-012c-af2e-0023dfa0a208quot;, quot;uriquot;:quot;/todos/9216df80-0c7b-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:13:04 GMTquot;, quot;documentquot;:quot;{quot;titlequot;:quot;fooquot;}quot; } ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 130. $ curl -i -XDELETE -H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' http://localhost:9292/todos/abc
  • 131. $ curl -i -XDELETE -H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' http://localhost:9292/todos/abc HTTP/1.1 200 OK Cache-Control: no-cache Content-Type: application/json Content-Length: 92 { quot;okquot;:true, quot;uriquot;:quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;etagquot;: quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:33:50 GMTquot; }
  • 132. $ curl -i -XDELETE -H'If-Match:55286040-0c7d-012c-af2e-0023dfa0a208' http://localhost:9292/todos/abc HTTP/1.1 200 OK Cache-Control: no-cache Content-Type: application/json Content-Length: 92 { quot;okquot;:true, quot;uriquot;:quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;etagquot;: quot;55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;last_modifiedquot;:quot;Thu, 16 Apr 2009 06:33:50 GMTquot; }
  • 133. $ curl -i http://localhost:9292/todos/abc
  • 134. $ curl -i http://localhost:9292/todos/abc HTTP/1.1 410 Gone Link: <http://localhost:9292/todos/abc/versions>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/versionsquot; Cache-Control: no-cache Content-Type: application/json Content-Length: 37 {quot;errorquot;:quot;entity previously deletedquot;}
  • 135. $ curl -i http://localhost:9292/todos/abc/versions
  • 136. $ curl -i http://localhost:9292/todos/abc/versions HTTP/1.1 200 OK Last-Modified: Thu, 16 Apr 2009 06:25:41 GMT ETag: quot;22116ccbc80e6356aec956be63c9c440quot; Link: <http://localhost:9292/todos/abc/versions/_resolved>; rel=quot;http://joncrosby.me/cloudkit/1.0/rel/resolvedquot; Cache-Control: proxy-revalidate Content-Type: application/json Content-Length: 157 { quot;urisquot;:[ quot;/todos/abc/versions/55286040-0c7d-012c-af2e-0023dfa0a208quot;, quot;/todos/abc/versions/f4538ca0-0c7b-012c-af2e-0023dfa0a208quot; ], quot;totalquot;:2, quot;offsetquot;:0 }
  • 144. Ability to Ask Questions
  • 148. Uniform Interface ... for querying?
  • 149. JSONQuery Kris Zyp http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/
  • 150. XPath
  • 152. Array Slice Operators /todos[10:20]
  • 153. Array Slice Operators /todos[10:20:2]
  • 162. var store = $.cloudkit; store.boot({ success: function() { // do something }, error: function(status) { // fail gracefully } });
  • 163. var store = $.cloudkit; store.boot({ success: function() { // do something }, error: function(status) { // fail gracefully } });
  • 164. var store = $.cloudkit; store.boot({ success: function() { // do something }, error: function(status) { // fail gracefully } });
  • 165. store.boot 1) Local collection per remote collection 2) Loads remote data
  • 166. store.boot 1) Local collection per remote collection 2) Loads remote data
  • 167. store.boot 1) Local collection per remote collection 2) Loads remote data
  • 168. var store = $.cloudkit; store.boot({ success: function() { // do something }, error: function(status) { // fail gracefully } });
  • 169. var store = $.cloudkit; store.boot({ success: function() { // do something }, error: function(status) { // fail gracefully } });
  • 170. // insert a 'todo' store.collection('todos').create({name:quot;fooquot;}, { success: function(todo) { // do something with the todo alert(todo.json().name); } });
  • 171. // insert a 'todo' store.collection('todos').create({name:quot;fooquot;}, { success: function(todo) { // do something with the todo alert(todo.json().name); } });
  • 172. // insert a 'todo' store.collection('todos').create({name:quot;fooquot;}, { success: function(todo) { // do something with the todo alert(todo.json().name); } });
  • 173. // insert a 'todo' store.collection('todos').create({name:quot;fooquot;}, { success: function(todo) { // do something with the todo alert(todo.json().name); } });
  • 174. // insert a 'todo' store.collection('todos').create({name:quot;fooquot;}, { success: function(todo) { // do something with the todo alert(todo.json().name); } });
  • 175. // update the 'todo' todo.update({name:quot;barquot;} { success: function() { // updated remotely, ready for use alert(todo.json().name); // now “bar” }, error: function(status) { // fail gracefully or recover } });
  • 176. // update the 'todo' todo.update({name:quot;barquot;} { success: function() { // updated remotely, ready for use alert(todo.json().name); // now “bar” }, error: function(status) { // fail gracefully or recover } });
  • 177. // update the 'todo' todo.update({name:quot;barquot;} { success: function() { // updated remotely, ready for use alert(todo.json().name); // now “bar” }, error: function(status) { // fail gracefully or recover } });
  • 178. // update the 'todo' todo.update({name:quot;barquot;} { success: function() { // updated remotely, ready for use alert(todo.json().name); // now “bar” }, error: function(status) { // fail gracefully or recover } });
  • 179. // update the 'todo' todo.update({name:quot;barquot;} { success: function() { // updated remotely, ready for use alert(todo.json().name); // now “bar” }, error: function(status) { // fail gracefully or recover } });
  • 180. Recovery 410 => Remove Locally? Create New?
  • 181. Recovery 410 => Remove Locally? Create New? 412 => Progressive Diff/Merge
  • 182. Recovery 410 => Remove Locally? Create New? 412 => Progressive Diff/Merge (Sync)
  • 183. // delete the 'todo' todo.destroy({ success: function() { // the 'todo' has now been deleted } });
  • 184. // delete the 'todo' todo.destroy({ success: function() { // the 'todo' has now been deleted } });
  • 185. // delete the 'todo' todo.destroy({ success: function() { // the 'todo' has now been deleted } });
  • 186. // delete the 'todo' todo.destroy({ success: function() { // the 'todo' has now been deleted } });
  • 188.
  • 189. Johnson Ruby/JavaScript Bridge http://github.com/jbarnette/johnson
  • 191. JSONSchema /:collection/_schema http://www.json.com/json-schema-proposal/
  • 192. { quot;descriptionquot;:quot;A personquot;, quot;typequot;:quot;objectquot;, quot;propertiesquot;: { quot;namequot;: { quot;typequot;:quot;stringquot; }, quot;agequot;: { quot;typequot;:quot;integerquot;, quot;maximumquot;:125 } } }
  • 197. OpenID + OAuth + OAuth/Discovery
  • 198. Browser OAuth OpenID Service
  • 199. Browser OAuth OpenID Service
  • 200. Browser {...} OAuth OpenID Service
  • 201. Browser OAuth OpenID Service
  • 202. Browser OAuth OpenID Service {...} Login
  • 203.
  • 204. Browser OAuth OpenID Service
  • 205. Browser OAuth OpenID Service
  • 206. Browser OAuth OpenID Service
  • 207. Service or Desktop App OAuth OpenID Service
  • 208. Service or Desktop App OAuth OpenID Service
  • 209. Service or Desktop App {...} OAuth OpenID Service
  • 210. Service or Desktop App OAuth OpenID Service
  • 211. Service or Desktop App OAuth OpenID Service {...} Login
  • 212. curl -i http://localhost:9292/todos HTTP/1.1 401 Unauthorized Connection: close Date: Thu, 15 Jan 2009 22:24:23 GMT WWW-Authenticate: OAuth realm=quot;http://localhost:9292quot; Link: <http://localhost:9292/oauth/meta>; rel=quot;http://oauth.net/discovery/1.0/rel/providerquot; Content-Type: text/html Set-Cookie: rack.session=d6b1c6aa6d463a478eb9af0e921eb997; path=/; HttpOnly Content-Length: 1280 <!DOCTYPE html PUBLIC quot;-//W3C//DTD XHTML 1.0 Transitional//ENquot; quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtdquot;> <html xmlns=quot;http://www.w3.org/1999/xhtmlquot; xml:lang=quot;enquot; lang=quot;enquot;> ... etc ...
  • 213. $ curl -i http://localhost:9292/oauth/meta
  • 214. $ curl -i http://localhost:9292/oauth/meta <?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?> <XRD> <Type>http://oauth.net/discovery/1.0</Type> <Service> <Type>http://oauth.net/discovery/1.0/rel/provider</Type> <URI>http://localhost:9292/oauth</URI> </Service> </XRD>
  • 215. $ curl -i http://localhost:9292/oauth
  • 217. <?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?> <XRDS xmlns=quot;xri://$xrdsquot;> <XRD xml:id=quot;oauthquot; xmlns:simple=quot;http://xrds-simple.net/core/1.0quot; xmlns=quot;xri://$XRD*($v*2.0)quot; version=quot;2.0quot;> <Type>xri://$xrds*simple</Type> <Expires>2009-02-14T22:27:50Z</Expires> <Service priority=quot;10quot;> <Type>http://oauth.net/core/1.0/endpoint/request</Type> <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> <URI>http://localhost:9292/oauth/request_tokens</URI> </Service> <Service priority=quot;10quot;> <Type>http://oauth.net/core/1.0/endpoint/authorize</Type> <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> <URI>http://localhost:9292/oauth/authorization</URI> </Service> <Service priority=quot;10quot;> <Type>http://oauth.net/core/1.0/endpoint/access</Type> <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> <URI>http://localhost:9292/oauth/access_tokens</URI> </Service> <Service priority=quot;10quot;> <Type>http://oauth.net/core/1.0/endpoint/resource</Type> <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> </Service> <Service priority=quot;10quot;> <Type>http://oauth.net/discovery/1.0/consumer-identity/static</Type> <LocalID>cloudkitconsumer</LocalID> </Service> </XRD> <XRD xmlns=quot;xri://$XRD*($v*2.0)quot; version=quot;2.0quot;> <Type>xri://$xrds*simple</Type> <Service priority=quot;10quot;> <Type>http://oauth.net/discovery/1.0</Type> <URI>#oauth</URI> </Service> </XRD> </XRDS>
  • 218. Service or Desktop App OAuth OpenID Service
  • 219. Service or Desktop App OAuth OpenID Service
  • 220. Service or Desktop App OAuth OpenID Service
  • 221. Service or Desktop App OAuth OpenID Service
  • 222. 1.0
  • 226. Done

Editor's Notes