Examples of Collection Storage Resources Last modified 12:50 ET January 7, 2008 Assumptions: - Jazz is running at http://example.com - client has already been authenticated as a user named Zoe - existing project /jazz/projects/main - zoe is authorized to work in project main - extant collection resource at /jazz/resources/main/root - strings like "[xxx]" indicate a specific value, like a timestamp or e-tag. The particulars are less interesting that the fact that these values reoccur in various requests and response in predictable ways. Each step shows 1 round trip from client to server. ========================================== Note that the Text in [TestCase.Operation] represents a cross-reference into the Open Resource Services test suite to ensure coverage of the examples below. These examples show the AtomPub style of resource creation. Rather than start with collection creation, the example begins by assuming that a collection already exists at the path "/jazz/resources/main/root", and shows how new non-collection resources can be added to the collection. STEP 1 Use GET to retrieve a representation of the collection resource (and atom:feed document). [AtomTests.testCreateNewFeed] GET /jazz/resources/main/root HTTP/1.1 Host: example.com Authorization: [zoe's credential] Date: [t10] HTTP/1.1 200 OK Date: [t10] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag0] Last-Modified: [t0] [urn:uuid identifying /jazz/resources/main/root collection resource] root [t0] [somebody] The representation shows that the collection is empty (no atom:entry elements in the atom:feed). A POST of a regular resource creates a pair of resources. The Entry resource shows up in the collection, and the Media resource is the one that holds the resource representation. STEP 2 Create a resource in the collection /jazz/resources/main/root using POST, suggesting that "file1" be its simple name. [AtomTests.testAddToFeed] POST /jazz/resources/main/root HTTP/1.1 Host: example.com Date: [t20] Authorization: [zoe's credentials] Content-Type: text/plain Content-Length: [nnn] Slug: file1 Whiter shade of pale. HTTP/1.1 201 CREATED Date: [t20] Content-Length: [nnn] Content-Type: application/atom+xml;type=entry Location: /jazz/resources/main/root/file1.entry Content-Location /jazz/resources/main/root/file1.entry ETag: [tag20] Last-Modified: [t20] [urn:uuid identifying /jazz/resources/main/root/file1.entry resource] file1 [t20] Zoe The server creates the Entry resource at /jazz/resources/main/root/file1.entry, adds it to the collection, and returns its representation. The server also creates the Media resource at /jazz/resources/main/root/file1, and links to it from the Entry resource. STEP 3 Retrieve the Entry resource at /jazz/resources/main/root/file1. GET /jazz/resources/main/root/file1 HTTP/1.1 Host: example.com Date: [t30] Authorization: [zoe's credentials] HTTP/1.1 200 OK Date: [t30] Content-Type: text/plain Content-Length: [nnn] ETag: [tag20-media] Last-Modified: [t20] Whiter shade of pale. A representation of the media resource was successfully retrieved. STEP 3A Retrieve the Media resource at /jazz/resources/main/root/file1.entry. GET /jazz/resources/main/root/file1.entry HTTP/1.1 Host: example.com Date: [t31] Authorization: [zoe's credentials] HTTP/1.1 200 OK Date: [t31] Content-Type: application/atom+xml;type=entry Content-Length: [nnn] ETag: [tag20] Last-Modified: [t20] [urn:uuid identifying /jazz/resources/main/root/file1.entry resource] file1 [t20] Zoe A representation of the entry resource was successfully retrieved. STEP 3B The client now updates the Entry resource at /jazz/resources/main/root/file1.entry adding an atom:category element. PUT /jazz/resources/main/root/file1.entry HTTP/1.1 Host: example.com Date: [t32] Authorization: [zoe's credentials] Content-Type: application/atom+xml;type=entry Content-Length: [nnn] If-Match: [tag20] If-Unmodified-Since: [t20] file1 HTTP/1.1 200 OK Date: [t32] Content-Length: [nnn] Location: /jazz/resources/main/root/file1.entry Content-Location: /jazz/resources/main/root/file1.entry ETag: [tag32] Last-Modified: [t32] [urn:uuid identifying /jazz/resources/main/root/file1.entry resource] file1 [t32] Zoe The representation shows that the collection now has a member resource, /jazz/resources/main/root/file1.entry. STEP 4 Retrieve the collection at /jazz/resources/main/root. GET /jazz/resources/main/root HTTP/1.1 Host: example.com Authorization: [zoe's credentials] Date: [t40] HTTP/1.1 200 OK Date: [t40] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag32] Last-Modified: [t32] [urn:uuid identifying /jazz/resources/main/root collection resource] root [t20] [somebody] [urn:uuid identifying resource /jazz/resources/main/root/file1.entry] file1 [t32] Zoe The representation shows that the collection now has a member resource. Note that although the atom:entry was last modified at t32, the atom:feed itself was considered to have been last modified at t20 when an entry was added. Updating an entry is not considered a significant update to the containing collection. STEP 5 Update the Media resource at /jazz/resources/main/root/file1. PUT /jazz/resources/main/root/file1 HTTP/1.1 Host: example.com Date: [t50] Authorization: [zoe's credentials] If-Match: [tag20-media] If-Unmodified-Since: [t20] Content-Type: text/plain Content-Length: [nnn] Walk away Renee. HTTP/1.1 204 No content Date: [t50] Content-Length: [nnn] The resource was successfully updated. STEP 6 Retrieve the collection at /jazz/resources/main/root. GET /jazz/resources/main/root HTTP/1.1 Host: example.com Authorization: [zoe's credentials] Date: [t60] HTTP/1.1 200 OK Date: [t60] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag50] Last-Modified: [t50] [urn:uuid identifying /jazz/resources/main/root collection resource] root [t20] [somebody] [urn:uuid identifying resource /jazz/resources/main/root/file1.entry] file1 [t50] Zoe The representation has an atom:entry with an atom:updated element changed since last time (but is otherwise the same). The atom:updated element of the atom:feed itself is unchanged. STEP 7 Delete the resource at /jazz/resources/main/root/file1, using preconditions which fail. DELETE /jazz/resources/main/root/file1 HTTP/1.1 Host: example.com Date: [t70] Authorization: [zoe's credentials] If-Match: [tag20] If-Unmodified-Since: [t20] HTTP/1.1 409 CONFLICT Date: [t70] Content-Length: [nnn] The operation fails because the resource has been updated in between. STEP 8 Delete the resource at /jazz/resources/main/root/file1 again, using preconditions which pass. DELETE /jazz/resources/main/root/file1 HTTP/1.1 Host: example.com Date: [t80] Authorization: [zoe's credentials] If-Match: [tag50-media] If-Unmodified-Since: [t50] HTTP/1.1 204 No content Date: [t80] Content-Length: [nnn] The resource was successfully deleted. STEP 9 Check that the resource at /jazz/resources/main/root/file1 has gone away (without a trace). HEAD /jazz/resources/main/root/file1 HTTP/1.1 Host: example.com Date: [t90] Authorization: [zoe's credentials] HTTP/1.1 404 Not found Date: [t90] Content-Length: [nnn] It Worked. STEP 10 Retrieve the collection /jazz/resources/main/root. GET /jazz/resources/main/root HTTP/1.1 Host: example.com Authorization: [zoe's credentials] Date: [t60] HTTP/1.1 200 OK Date: [t100] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag80] Last-Modified: [t80] [urn:uuid identifying /jazz/resources/main/root collection resource] root [t80] [somebody] The resource has disappeared from the collection. ========================================== These are the basic mechanics of adding a non-collection resource to a collection, updating the resource, and deleting it. The following steps show how new collection resources are created. There are 2 different ways in which a collection resource can be created. Create a collection by PUTing to a client-supplied URI. Create a collection by POSTing to an existing collection. We'll show case (2) first, since it's the more similar to above. STEP 11 Create a new collection resource in the collection /jazz/resources/main/root using POST, suggesting that "bin1" be its simple name. POST /jazz/resources/main/root HTTP/1.1 Host: example.com Date: [t110] Authorization: [zoe's credentials] Content-Type: application/atom+xml Content-Length: [nnn] Slug: bin1 bin1 HTTP/1.1 201 CREATED Date: [t110] Content-Length: [nnn] Location: /jazz/resources/main/root/bin1 Content-Type: application/atom+xml;type=entry Location: /jazz/resources/main/root/bin1.entry Content-Location /jazz/resources/main/root/bin1.entry ETag: [tag110] Last-Modified: [t110] [urn:uuid identifying /jazz/resources/main/root/bin1.entry resource] bin1 [t110] Zoe The server creates the collection resource at /jazz/resources/main/root/bin1 and the Entry resource /jazz/resources/main/root/bin1.entry, adds the resource to the root collection, and returns a representation of the Entry resource. STEP 12 Retrieve the new collection resource at /jazz/resources/main/root/bin1. GET /jazz/resources/main/root/bin1 HTTP/1.1 Host: example.com Date: [t120] Authorization: [zoe's credentials] HTTP/1.1 200 OK Date: [t120] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag110-media] Last-Modified: [t110] [urn:uuid identifying the new collection resource] bin1 [t110] Zoe A representation of the new collection resource was successfully retrieved. STEP 13 Retrieve the collection /jazz/resources/main/root. GET /jazz/resources/main/root HTTP/1.1 Host: example.com Authorization: [zoe's credentials] Date: [t130] HTTP/1.1 200 OK Date: [t130] Content-Type: application/atom+xml Content-Length: [nnn] ETag: [tag110] Last-Modified: [t110] [urn:uuid identifying /jazz/resources/main/root collection resource] root [t110] [somebody] [urn:uuid identifying resource /jazz/resources/main/root/bin1.entry] bin1 [t110] Zoe The representation shows that the root collection now has the new collection resource as a member. STEP 14 Create a resource in the collection /jazz/resources/main/root/bin1 using POST, suggesting that "file2" be its simple name. POST /jazz/resources/main/root/bin1 HTTP/1.1 Host: example.com Date: [t140] Authorization: [zoe's credentials] Content-Type: text/plain Content-Length: [nnn] Slug: file2 Sitting on the dock of the bay. HTTP/1.1 201 CREATED Date: [t140] Content-Length: [nnn] Location: /jazz/resources/main/root/bin1/file2.entry Content-Location: /jazz/resources/main/root/bin1/file2.entry ETag: [tag140] Last-Modified: [t140] [urn:uuid identifying /jazz/resources/main/root/bin1/file2.entry resource] file2 [t140] Zoe The server creates the Entry resource at /jazz/resources/main/root/bin1/file2.entry and adds it to the collection. It also creates the Media resource at /jazz/resources/main/root/bin1/file2. STEP 15 Slam the collection resource at /jazz/resources/main/root/bin1 to be a non-collection. [ClobberTests.testSafeSimpleOverAtom] PUT /jazz/resources/main/root/bin1 HTTP/1.1 Host: example.com Date: [t150] Authorization: [zoe's credentials] Content-Type: text/plain Content-Length: [nnn] If-Match: [tag140-media] If-Unmodified-Since: [t140] These boots are made for walkin'. HTTP/1.1 405 Method not allowed Date: [t50] Allow: GET, HEAD, POST, DELETE Content-Length: [nnn] The server disallows a change that would replace the collection resource with a non-collection resource. To do this, the client would need to delete the existing collection resource, and then create a non-collection resource in its place. STEP 16 Slam the non-collection resource at /jazz/resources/main/root/bin1/file2 to be a collection. [ClobberTests.testSafeAtomOverSimple] PUT /jazz/resources/main/root/bin1/file2 HTTP/1.1 Host: example.com Date: [t160] Authorization: [zoe's credentials] Content-Type: application/atom+xml Content-Length: [nnn] If-Match: [tag140-media] If-Unmodified-Since: [t140] file2 HTTP/1.1 405 Method not allowed Date: [t160] Allow: GET, HEAD, POST, DELETE Content-Length: [nnn] The server disallows a change that would replace the non-collection resource with a collection resource. The client must delete the existing resource, and then create a collection resource in its place. STEP 17 Create a new collection resource at /jazz/resources/main/root/bin1/folder3 using PUT (the 2nd way to create collections). [AtomTests.testCreateUsingArbitraryUrl] PUT /jazz/resources/main/root/bin1/folder3 HTTP/1.1 Host: example.com Date: [t170] Authorization: [zoe's credentials] Content-Type: application/atom+xml Content-Length: [nnn] If-None-Match: * folder3 HTTP/1.1 201 CREATED Date: [t110] Location: /jazz/resources/main/root/bin1/folder3 Content-Length: [nnn] The server creates the collection resource at /jazz/resources/main/root/bin1/folder3. Since the new resource was not created by POSTing it to the collection at /jazz/resources/main/root/bin1, it is unaffiliated with that collection, despite the similar URIs. STEP 18 Delete the collection at /jazz/resources/main/root/bin1. [AtomTests.testCreateUsingArbitraryUrl] DELETE /jazz/resources/main/root/bin1 HTTP/1.1 Host: example.com Date: [t180] Authorization: [zoe's credentials] If-Unmodified-Since: [t140] If_Match: [tag140-media] HTTP/1.1 204 No content Date: [t180] Content-Length: [nnn] The collection /jazz/resources/main/root/bin1 is successfully deleted along with its member resource /jazz/resources/main/root/bin1/file2. Note that the resource at /jazz/resources/main/root/bin1/file3 is unaffected. STEP 19 The client POSTs an Entry document to a collection resource. [AtomTests.testAddToFeed] POST /jazz/resources/main/root HTTP/1.1 Host: example.com Date: [t190] Authorization: [zoe's credentials] Content-Type: application/atom+xml;type=entry Slug: entry5 Content-Length: [nnn] entry5 The official US time HTTP/1.1 201 CREATED Date: [t190] Content-Length: [nnn] Location: /jazz/resources/main/root/entry5 Content-Location: /jazz/resources/main/root/entry5 ETag: [tag190] Last-Modified: [t190] [urn:uuid identifying /jazz/resources/main/root/entry5 resource] entry5 [t190] Zoe The official US time The server creates the Entry resource at /jazz/resources/main/root/entry5. The response includes the representation of the Entry resource. STEP 20 The client now updates the Entry resource at /jazz/resources/main/root/entry5 with out-of-line content. PUT /jazz/resources/main/root/entry5 HTTP/1.1 Host: example.com Date: [t200] Authorization: [zoe's credentials] Content-Type: application/atom+xml;type=entry Content-Length: [nnn] Slug: entry5 If-Match: [tag190] If-Unmodified-Since: [t190] entry5 Good morning starshine. HTTP/1.1 204 No data Date: [t200] Content-Length: [nnn] STEP 21 The client retrieves the resource-collection property for the Entry resource at /jazz/resources/main/root/entry5. GET /jazz/resources/main/root/entry5?properties=resource-collection HTTP/1.1 Host: example.com Date: [t210] Authorization: [zoe's credentials] /jazz/resources/main/root (End of examples.)