This repository has been archived by the owner on Jun 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
1-resttl.txt
757 lines (558 loc) · 39.6 KB
/
1-resttl.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
This document defines a RESTful Transport Layer (RestTL), a way of working with server-held resources in a RESTful fashion. RestTL specifies standard rules for representing resources, and standard mechanisms for working with them in a RESTful fashion over a plain HTTP client-server network.
* Name: www.restms.org/spec:1/RestTL
* Version: draft/4
* Editor: Pieter Hintjens <[email protected]>
* Contributors: Steve Vinoski <[email protected]>, Brad Clements <[email protected]>
++ License
Copyright (c) 2009 by the Editor and Contributors.
This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses>.
++ Change Process
This document is governed by the Digital Standard Organization's [http://www.digistan.org/spec:1/COSS Consensus-Oriented Specification System].
++ Goals and structure of this document
This document defines a RESTful Transport Layer (RestTL), a way of working with server-held resources in a RESTful fashion. RestTL specifies standard rules for representing resources, and standard mechanisms for working with them in a RESTful fashion over a plain HTTP client-server network.
RestTL is a foundation for arbitrary RESTful APIs including, but not limited to, RestMS. We describe:
# A set of HTTP requests and responses that let a client work with server-side resources in a RESTful way;
# A grammar for XML or JSON documents to represent server-held resources.
++ Language
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119[((bibcite rfc2119))].
These terms are introduced by, and have specific meaning, in this specification:
* Asynclet - a resource that can be retrieved before it exists, resulting in a "long poll".
++ Why define a RESTful Transport Layer?
REST[((bibcite rest))] is a design pattern rather than a formal specification. This means that architects have lattitude in how to implement more or less RESTful APIs. This is useful for experimentation but problematic for defining standards. Standards should formalize best practice in a regular way.
The principle of Least Surprise applies: the implementer, having learned the rules that apply to object A, expects them to apply to object B insofar as that makes sense. How we create and work with resources, how we name and address resources, how we represent resources: all these should as regular as possible. We do not want discussions over whether one updates a resource using PUT or POST.
The best way to enforce the regularity of such rules is to draw them out into a stand-alone specification, and document them clearly, removing redundant optionality so there is exactly one way to do anything, and no grey areas. This is such a specification.
While RestTL was designed to support [[[spec:2|RestMS]]], it is not restricted to that use case, and could be used to build other RESTful APIs. At the same time, RestTL does not claim to be a universal RESTful transport: it abstracts sufficient design to support RestMS, and no more.
+++ RestTL overview
We speak of "the API" as being a RESTful protocol that we layer on top of RestTL.
RestTL is built on HTTP/HTTPS and conforms to the HTTP/1.1 specifications. It implements these HTTP methods:
* POST - create a new resource
* GET - retrieve a resource
* PUT - update a resource
* DELETE - delete a resource
It uses these HTTP headers with their HTTP/1.1 meaning:
* Location - URI of newly created resource
* ETag - opaque hash tag of that identifies a resource instance
* Data-Modified - date and time that resource was modified
* If-Modified-Since - conditional GET using resource date
* If-None-Match - conditional GET using resource ETag
* If-Unmodified-Since - conditional PUT or DELETE using resource date
* If-Match - conditional PUT or DELETE using resource ETag
Additionally, it uses two custom headers to allow event-driven work:
* When-Modified-After - GET evented on resource date change
* When-None-Match - GET evented on resource ETag change
RestTL assumes the availability of standard HTTP client and server stacks that can handle headers such as Content-Length properly.
API resources are either //public// (shared by many clients) or //private// (to a single client). Public resources are named by formal or informal agreement, while the server is responsible for naming all private resources. The URI of a resource is based on the resource name, so clients can know the URIs of public resources in advance, while the server provides the URIs of private resources at runtime.
API resources are either //structured// or //opaque//. A structured resource has properties that both client and server can access and modify. Resources can contain references (URIs) to child resources. An opaque resource has a MIME type and a binary content that the API never examines nor modifies.
The API resource types form a static //type tree// attached to a root type. The set of actual resources that a server holds form a dynamic //resource tree//, attached to a public root resource. To navigate the resource tree, clients retrieve the root resource and inspecting it. Not all resources are discoverable: to work with a private resource an client must have created it, and thus know its URI.
The API represents structured resources as interchangeable XML or JSON //resource documents//, at the choice of the client. These documents follow simple grammar rules for representing resources and their properties.
Lastly the API has two mechanisms for evented asynchronous retrieval and delivery of resources, and one mechanism for event-driven monitoring of resource updates. RESTful APIs, like HTTP, are nominally synchronous and use a request-response pattern for all resource actions. The first mechanism is the //asynclet// resource, given a URI before it exists: the client retrieves the asynclet and receives the resource as soon as it comes into existence. The second mechanism is more typical for HTTP: //streaming// of new resources to the client. Lastly, using special HTTP headers a client can ask to be notified when a resource is changed.
++ HTTP requests and responses
Clients issue HTTP methods to work with server-side resources as follows:
* the GET method to retrieve the representation of a known resource;
* the POST method to create a new, dynamically named resource;
* the PUT method to edit a known resource;
* the DELETE method to remove a known resource.
All methods work orthogonally on all types of API resources, whether those resources contain or do not contain other resources. Not all combinations of methods and resources are meaningful, permitted, or necessarily implemented in any eventual API based on RestTL. This framework draws on the design of AtomPub[((bibcite atompub))], which may be helpful as background material.
+++ Resource lifecycles, visibility, and addressing
API resources can be created by various parties at different times: by the server at startup, by clients at runtime, or by the server as the consequence of other events, at runtime. Only the party that created a resource can delete it, and it may place restrictions on other parties' right to work with the resource.
RestTL distinguishes between resources that are named and visible to all applications ("public resources") and resources that are unnamed and accessed via server-defined URI ("private resources").
The URI for a public resource is derived from the resource type and name as follows:
[[code]]
http://{server name}[:{port}]/{schema}/{resource type}/{resource name}
[[/code]]
The fields have this meaning:
* server name - name of host as for HTTP request
* port - optional port as for HTTP request
* schema - name of the API
* resource type - name of the resource type
* resource name - name of the resource itself
The URI for a private resource follows an identical format, where resource type is "resource" and resource name is a hash generated by the server:
[[code]]
http://{server-name}[:{port}]/{schema}/resource/{resource hash}
[[/code]]
+++ Creating a resource
Clients create new resources through the API as follows:
* The client must know the URI of the parent for the new resource it wants to create.
* The client POSTs a specification for the new resource to the parent URI.
* The client creates a public resource by specifying a name. Otherwise the server names the resource.
* The server either returns 2xx with a resource document, or 4xx or 5xx with an error text.
* The server when it creates the resource returns "201 Created" with the new URI in the Location: header.
[[code]]
Client Server
| |
| 1.) POST to parent URI |
| Resource specifications |
|------------------------------------------>|
| |
| 2.) 201 Created |
| Location: Resource URI |
|<------------------------------------------|
| |
[[/code]]
The content body of the created resource may be different than the content body provided by the client. While the client provides specifications for the resource, the server returns the actual resulting resource, which may have additional properties and/or children.
This is the general form of a client HTTP request to create a dynamic resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:
[[code]]
Client:
-------------------------------------------------
POST /{parent uri} HTTP/1.1
Content-Type: application/{schema}+xml
<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
<{resource type} [name = "{name for public resource}"]>
{resource specifications}
</{resource type}>
</{schema}>
Server:
-------------------------------------------------
HTTP/1.1 201 Created
Content-Type: application/{schema}+xml
Date-Modified: {resource date and time}
ETag: {resource entity tag}
Location: {resource URI}
<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
<{resource type} name="{resource name}"...>
{resource contents}
</{resource type}>
</{schema}>
[[/code]]
The server may return these response codes specifically for a POST request:
* 200 OK - the resource already existed as specified (only possible for public resources).
* 201 Created - the server created the resource, and the Location: header provides the URI.
* 400 Bad Request - the resource specification was incomplete or badly formatted.
* 403 Forbidden - the POST method is not allowed on the parent URI.
In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.
Creating public resources is //idempotent//, i.e. repeated requests to create the same public resource are allowed, and safe. Clients should treat "200 OK" and "201 Created" as equally successful.
+++ Retrieving a resource
Clients retrieve resources through the API as follows:
* The client must know the URI of the resource that it wants to retrieve.
* The client sends a GET method to the resource URI.
* The client optionally specifies headers to do a conditional retrieval (caching).
* The server either returns "200 OK" with a resource document, "304 Not Modified" with no content, or 4xx or 5xx with an error text.
[[code]]
Client Server
| |
| 1.) GET to Resource URI |
|------------------------------------------>|
| |
| 2.) 200 Ok |
| Resource representation |
|<------------------------------------------|
| |
[[/code]]
This is the general form of an unconditional client HTTP request to retrieve a resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:
[[code]]
Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/{schema}+xml
Date-Modified: {resource date and time}
ETag: {resource entity tag}
<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
<{resource type} ...>
{resource contents}
</{resource type}>
</{schema}>
[[/code]]
The server may return these response codes specifically for a GET request:
* 200 OK - the resource already existed as specified (only for public resources).
* 304 Not Modified - the client already has the latest copy of the resource.
* 400 Bad Request - the resource document was incomplete or badly formatted.
In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.
//Conditional retrieval// is used to cache resources and fetch them only if they have changed. Clients retrieve resources conditionally as follows:
* The client must previously have retrieved the resource.
* The client does a GET method with If-None-Match: and If-Modified-Since: headers.
* The server returns "200 OK" and the resource document if the client's copy is out of date.
* The server returns "304 Not Modified" with no content if the client's copy is up-to-date.
This is the general form of a client HTTP request to conditionally retrieve a resource:
[[code]]
Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
If-None-Match: {resource entity tag}
If-Modified-Since: {resource date and time}
[[/code]]
A conditional get only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-None-Match: or If-Modified-Since: headers but for best results, use both.
Retrieving a resource has //no side effects//, i.e. repeated requests to retrieve the same resource will provoke the same responses, unless a third party deletes or modifies the resource.
+++ Updating a resource
Clients update resources through the API as follows:
* The client must know the URI of the resource that it wants to update.
* The client should have retrieved the resource before updating it.
* The client sends a PUT method to the resource URI with the modified resource document.
* The client optionally specifies headers to do a conditional update.
* The server either returns 2xx with a resource document, or 4xx or 5xx with an error text.
[[code]]
Client Server
| |
| 1.) GET to Resource URI |
|------------------------------------------>|
| |
| 2.) 200 OK |
| Resource representation |
|<------------------------------------------|
| |
| 3.) PUT to Resource URI |
| Modified resource representation |
|------------------------------------------>|
| |
| 4.) 200 OK |
|<------------------------------------------|
[[/code]]
This is the general form of a client HTTP request to unconditionally modify a resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:
[[code]]
Client:
-------------------------------------------------
PUT /{resource uri} HTTP/1.1
Content-Type: application/{schema}+xml
<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
<{resource type} ...>
{resource contents}
</{resource type}>
</{schema}>
Server:
-------------------------------------------------
HTTP/1.1 200 OK
Date: {response date}
[[/code]]
The server may return these response codes specifically for a PUT request:
* 200 OK - the resource was successfully updated.
* 204 No Content - the client provided no resource document and the update request had no effect.
* 400 Bad Request - the resource document was incomplete or badly formatted.
* 403 Forbidden - the PUT method is not allowed on the resource.
* 412 Precondition Failed - the client does not have the latest copy of the resource.
In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.
//Conditional update// is used to detect and prevent update conflicts (when multiple clients try to update the same resource at the same time). Clients conditionally update resources conditionally as follows:
* The client must previously have retrieved the resource.
* The client does a DELETE method with If-Match: and If-Unmodified-Since: headers.
* The server returns "412 Precondition Failed" if the client's copy is out of date.
* The server returns "200 OK" and the new resource document if the client's copy was up-to-date.
This is the general form of a client HTTP request to conditionally update a resource:
[[code]]
Client:
-------------------------------------------------
PUT /{resource uri} HTTP/1.1
If-Match: {resource entity tag}
If-Unmodified-Since: {resource date and time}
[[/code]]
A conditional PUT only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-Match: or If-Unmodified-Since: headers but for best results, use both.
Modifying resources is //idempotent//, i.e. repeated requests to modify the same resource are allowed, and safe, unless a third party modifies or deletes the resource.
+++ Deleting a resource
Clients delete resources through the API as follows:
* The client must know the URI of the resource that it wants to delete.
* The client should have retrieved the resource before delete it.
* The client sends a DELETE method to the resource URIt.
* The client optionally specifies headers to do a conditional delete.
* The server either returns "200 OK", or 4xx or 5xx with an error text.
[[code]]
Client Server
| |
| 1.) GET to Resource URI |
|------------------------------------------>|
| |
| 2.) 200 OK |
| Resource representation |
|<------------------------------------------|
| |
| 3.) DELETE to resource URI |
|------------------------------------------>|
| |
| 4.) 200 OK |
|<------------------------------------------|
| |
[[/code]]
This is the general form of a client HTTP request to unconditionally delete a resource, with the server response. We ignore standard HTTP headers:
[[code]]
Client:
-------------------------------------------------
DELETE /{resource uri} HTTP/1.1
Server:
-------------------------------------------------
HTTP/1.1 200 OK
[[/code]]
The server may return these response codes specifically for a DELETE request:
* 200 OK - the resource was successfully updated.
* 403 Forbidden - the DELETE method is not allowed on the resource.
* 412 Precondition Failed - the client does not have the latest copy of the resource.
In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.
//Conditional delete// is used to detect and prevent delete conflicts (when multiple clients try to delete the same resource at the same time). Clients conditionally delete resources conditionally as follows:
* The client must previously have retrieved the resource.
* The client does a DELETE method with If-Match: and If-Unmodified-Since: headers.
* The server returns "412 Precondition Failed" if the client's copy is out of date.
* The server returns "200 OK" if the client's copy was up-to-date.
This is the general form of a client HTTP request to conditionally delete a resource:
[[code]]
Client:
-------------------------------------------------
DELETE /{resource uri} HTTP/1.1
If-Match: {resource entity tag}
If-Unmodified-Since: {resource date and time}
[[/code]]
A conditional DELETE only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-Match: or If-Unmodified-Since: headers but for best results, use both.
Deleting resources is //idempotent//, i.e. repeated requests to delete the same resource are allowed, and safe. Implementations may cache the URIs of deleted resources in order to differentiate between deletes on already-deleted resources, and deletes on resources that never existed.
If the resource to be deleted contains other resources, these are implicitly and silently deleted along with the resource.
+++ MIME types
When the client retrieves a resource it MAY specify which MIME type it desires using the Accept header. While the HTTP specification (RFC 2616 section 14.1[((bibcite rfc2616))]) defines a complex format for the Accept header, RestTL allows these three possibilities:
* "Accept: application/{schema}+xml"
* "Accept: application/{schema}+json"
* "Accept: text/xml", which is equivalent to no Accept: header.
The server will respond with a resource document in the requested format and a Content-Type: header of the appropriate type. Note that most browsers will display "text/xml" documents as XML, while they will not show "application/{schema}+xml". Thus it is possible to embed RestTL resource URIs in, for example, HTML documents, with usable results.
When a client creates a new resource or modifies an existing resource, it SHOULD specify the MIME type of the resource document that it is sending to the browser, using the Content-Type header. RestTL allows the same three values as for the Accept: header:
* "Content-Type: application/{schema}+xml"
* "Content-Type: application/{schema}+json"
* "Content-Type: text/xml", which is equivalent to no Content-Type: header.
When a client deletes a resource neither the Accept: nor Content-Type: headers have any significance, and MUST be ignored by the server.
If a server does not support the content type requested or provided by the client, it SHOULD return "501 Not Implemented."
+++ Asynchronous retrieval
HTTP is generally a synchronous protocol in which a client polls a server for resources. This is undesirable in many architectures, both from a design and a performance perspective. RestTL allows three mechanisms for asynchronous non-polled resource delivery. In each case, the client sends a GET to the server, which responds only when some condition (an event) is true. Some sources call this "long polling".
The three asynchronous delivery mechanisms are:
# //Streaming//, in which a resource is delivered in segments, over time. RestTL has no specific support for streaming: it is implemented using multipart contents, but otherwise looks like a conventional resource GET.
# //Creation notification//, in which a resource is delivered only when it is created. RestTL implements this using "asynclets".
# //Update notification//, in which a resource is delivered only when it is changed. RestTL implements this using the custom When-Modified-After: and When-None-Match: headers.
++++ Creation notification via asynclets
An asynclet is an "asynchronous resource instance", which is a resource that is given a URI identifier //before// it exists. When the client retrieves the asynclet, the server will respond only when the resource has come into existence.
Asynclets are used in a specific case: when resources sit in some kind of a queue that is retrieved and emptied by the client (using GET and DELETE in a loop). The queue would be the parent resource, the container. The queue then contains zero or more existing resources plus a single asynclet.
A normal resource is identified in a parent resource by a href attribute, and other attributes:
[[code]]
<some-type href="some-URI" ... />
[[/code]]
An asynclet has the href attribute and a second attribute 'async="1"', telling the client that this resource, though it has a URI, does not in fact yet exist:
[[code]]
<some-type href="some-URI" async="1" />
[[/code]]
When the client retrieves an asynclet, the server waits until the resource is created, within that parent, and it then responds to the client with the contents of that new resource.
When the client retrieves the asynclet container, the container resource holds all existing resources plus a single asynclet:
[[code]]
<some-type href="some-URI-1" ... />
<some-type href="some-URI-2" ... />
<some-type href="some-URI-3" ... />
<some-type href="some-URI-4" ... />
<some-type href="some-URI-5" async="1" />
[[/code]]
At any time a new resource may 'arrive' and the URI held by a client for an asynclet will then refer to a real existing resource. This is transparent to the client except that there will be no wait when the client issues a GET on that URI.
++++ Update notification
Applications can monitor specific resources for updates using two HTTP extension headers. If the client has already retrieved the resource it specifies the resource ETag:
[[code]]
Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
When-None-Match: {resource entity tag}
[[/code]]
The client can also specify the last-known modified date and time, the current date and time, or a later date and time:
[[code]]
Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
When-Modified-After: {resource date and time}
[[/code]]
The server will respond with the new resource document when it is modified. The client should be able to handle any HTTP error condition, such as "404 Not Found" or "501 Not Implemented". If both headers are specified, the server will respond only when both conditions are true.
The When-Modified-After: header was originally proposed in the Comet[((bibcite comet))] specification.
+++ Caching and ETags
RestTL assumes that all resources may be cached. We define two types of cache. First, the "end cache", is held in the browser or HTTP client layer. Second, the "proxy cache" is a service that sits between the client and the server.
The server can disallow (or at least discourage) both types of cache from holding content. It does this by adding a "Cache-Control: No-cache" header to the response.
The client can inform the server or proxy cache that it has cacheable content for a resource by specifying either one of, or both of, the If-Modified-Since and If-None-Match header together with an ETag. Usually, specifying both conditional headers gives best results.
ETags are calculated by the server. The ETag value for resources that can have multiple MIME representations MUST depend on the MIME type of the returned resource specification. Thus a resource returned as XML will have a different ETag than the same resource returned as JSON.
Note that if a proxy cache is enabled, clients will not be guaranteed to receive the freshest version of a resource for a GET method. There is no mechanism to push resource updates to proxy servers.
+++ Idempotency and side-effects
The GET, PUT, and DELETE methods are idempotent: the client can safely issue these more than once. POST is idempotent when creating public resources. POST to create private resources is not idempotent and will create one resource per successful execution.
Idempotency allows the client to safely recover from failures where it did not get a response, yet could not sure the server did not receive the request. For example, any failure in the network, the client, or an intermediary that happens after the server receives the request but before the client receives the response. The client recovers by simply reissuing any GET, PUT, DELETE, and POST-public requests that were not completed.
The GET method does not modify the state of any resource on the server.
+++ Pipelining
The client may send requests in parallel, which is called "pipelining". RFC 2616[((bibcite rfc2616))] section 8.1.2.2 says,
> Clients SHOULD NOT pipeline requests using non-idempotent methods or non-idempotent sequences of methods (see section 9.1.2). Otherwise, a premature termination of the transport connection could lead to indeterminate results. A client wishing to send a non-idempotent request SHOULD wait to send that request until it has received the response status for the previous request.
RestTL clients MAY pipeline GET, PUT, DELETE and POST-public methods, but SHOULD NOT pipeline POST-private methods.
+++ Error responses
When the server returns an error response (4xx or 5xx), the content body MUST be in plain text, and the MIME type MUST be "text/plain". The client can print and log the content body as a text with no parsing or decoding.
++ RestTL resource document grammar
Most, though not all, resources managed through a RestTL API are represented as structured resource documents.
In generally, a client sends a resource document to the server when it wishes to create a new resource or update a resource. The server sends a resource document to the client in response to a create, retrieve, or update request. Certain resources may be represented as opaque MIME-type blobs, in which case they are posted and retrieved as such, not as structured resource documents.
RestTL resource documents have a schema-independent regular grammar designed to support all the requirements of a RESTful API. The grammar makes it possible for applications to navigate the API as follows:
* Resources are typed, and the type names form the main element names in the document.
* A resource type may be a container for other resource types.
* This hierarchy of resource types forms a //static type tree// attached to a single root type.
* At runtime, the actual resources form a //dynamic resource tree// attached to a single root resource.
* Clients navigate the resource tree by retrieving the root resource.
* Resource documents may contain URI references to accessible child resources.
* A private resource is accessible only to the client that created it, and knows its URI.
Our goals with this design are:
* To define a document syntax that is easily mapped to arbitrary structured languages including XML and JSON.
* To provide documents that are navigable and discoverable with mimimum prior knowledge.
* To deliver the cheap parsing benefits of structured languages without the cost of formal validation.
* To allow unilateral extensibility of the resource hierarchy by server implementations.
* To keep things as simple as possible for RestTL application developers.
* To allow for future evolution in structured data representation.
+++ Basic syntax rules
RestTL resource documents obey these basic rules:
* All resource documents in an API are part of a //schema// that defines the type tree.
* The resource document has a //document root// element with the name of the schema.
* The document root contains zero or more //resource roots//.
* The resource root elements may contain other elements.
* All elements except the document root correspond to RestTL resources, with the name of the element equal to the resource type.
* Resource properties are represented as element attributes, not as child elements.
* All elements except the document root may repeat 0 or more times.
Further, for XML documents:
* The Content-type MUST be "application/{schema-name}+xml".
* The document root has a single attribute, xmlns="http://www.restms.org/schema/{schema-name}". Note that the schema does //not// need to exist.
* The following character MUST be escaped in attribute values:
* " (escaped by writing ")
And for JSON documents:
* The Content-type MUST be "application/{schema-name}+json".
* The following character MUST be escaped in value strings:
* " (escaped by writing \")
Here is an example of a RestTL document in XML, for a schema called "music":
[[code]]
<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
<playlist name = "default">
<album
artist="Echobelly" title="On" released="1995-10-17"
summary="Underrated, bittersweet guitar rock perfection">
<track title="Car Fiction" length="2:31" />
<track title="King of the Kerb" length="3:59" />
<track title="Great Things" length="3:31" />
<track title="Natural Animal" length="3:27" />
<track title="Go Away" length="2:44" />
<track title="Pantyhose and Roses" length="3:26" />
<track title="Something Hot in a Cold Country" length="4:01" />
<track title="Four Letter Word" length="2:51" />
<track title="Nobody Like You" length="3:52" />
<track title="In the Year" length="3:31" />
<track title="Dark Therapy" length="5:30" />
<track title="Worms and Angels" length="2:38" />
</album>
</playlist>
</music>
[[/code]]
The resource tree for the music schema is:
[[code]]
playlist
|
o- album
|
o- track
[[/code]]
Here is the same document in JSON:
[[code]]
{
"music": {
"playlist": [ { "name":"default",
"album": [ { "artist":"Echobelly", "title":"On", "released":"1995-10-17",
"summary":"Underrated, bittersweet guitar rock perfection",
"track": [
{ "title":"Car Fiction", "length":"2:31" },
{ "title":"King of the Kerb", "length":"3:59" },
{ "title":"Great Things", "length":"3:31" },
{ "title":"Natural Animal", "length":"3:27" },
{ "title":"Go Away", "length":"2:44" },
{ "title":"Pantyhose and Roses", "length":"3:26" },
{ "title":"Something Hot in a Cold Country", "length":"4:01" },
{ "title":"Four Letter Word", "length":"2:51" },
{ "title":"Nobody Like You", "length":"3:52" },
{ "title":"In the Year", "length":"3:31" },
{ "title":"Dark Therapy", "length":"5:30" },
{ "title":"Worms and Angels", "length":"2:38" }
] }
] }
] }
}
[[/code]]
Note that it is possible to map between JSON and XML without loss. The key issue for XML documents is that properties are represented as element attributes, not as child elements.
+++ Navigation and discovery
RestTL documents use the following rule to allow navigation and discovery:
* The attribute "href", if present, holds the URI for the resource that the element represents.
* The URI for the root resource is known to both client and server by common agreement.
* The URIs for all non-root resources are generated by the server and may be stored by the client.
* All URIs provided by the server are absolute. The client at the HTTP level should use URIs with no scheme or hostname.
Here is an example of a client retrieving a public playlist resource using a HTTP GET method, with the server's response. The server is at host.com:
[[code]]
Client:
-------------------------------------------------
GET /music/playlist/default HTTP/1.1
Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/music+xml
<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
<playlist name="default">
<album
artist="Echobelly" title="On"
href="http://host.com/music/resource/A1023" />
<album
artist="Muse" title="Showbiz"
href="http://host.com/music/resource/A0911" />
<album
artist="Toumani Diabate" title="Djelika"
href="http://host.com/music/resource/A0023" />
</playlist>
</music>
[[/code]]
To retrieve a specific album, the client uses the URI provided by the server, for example:
[[code]]
Client:
-------------------------------------------------
GET /music/resource/A1023 HTTP/1.1
Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/music+xml
<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
<album
artist="Echobelly" title="On" released="1995-10-17"
summary="Underrated, bittersweet guitar rock perfection"
<track title="Car Fiction" length="2:31"
href="http://host.com/music/resource/A1023/1" />
<track title="King of the Kerb" length="3:59"
href="http://host.com/music/resource/A1023/2" />
<track title="Great Things" length="3:31"
href="http://host.com/music/resource/A1023/3" />
<track title="Natural Animal" length="3:27"
href="http://host.com/music/resource/A1023/4" />
<track title="Go Away" length="2:44"
href="http://host.com/music/resource/A1023/5" />
<track title="Pantyhose and Roses" length="3:26"
href="http://host.com/music/resource/A1023/6" />
<track title="Something Hot in a Cold Country" length="4:01"
href="http://host.com/music/resource/A1023/7" />
<track title="Four Letter Word" length="2:51"
href="http://host.com/music/resource/A1023/8" />
<track title="Nobody Like You" length="3:52"
href="http://host.com/music/resource/A1023/9" />
<track title="In the Year" length="3:31"
href="http://host.com/music/resource/A1023/10" />
<track title="Dark Therapy" length="5:30"
href="http://host.com/music/resource/A1023/11" />
<track title="Worms and Angels" length="2:38"
href="http://host.com/music/resource/A1023/12" />
</album>
</music>
[[/code]]
To retrieve a specific track, the client once again uses the URI provided by the server. Note that in this case the server delivers a content of type "audio/mpeg-3", which the client should process accordingly (and not as RestTL XML or JSON):
[[code]]
Client:
-------------------------------------------------
GET http://host.com/music/resource/A1023/5 HTTP/1.1
Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Length: 2870112
Content-Type: audio/mpeg-3
...opaque binary content...
[[/code]]
+++ Handling unknown elements
Resource documents may contain elements, and unknown attributes on known elements. This is especially likely when the client and server implement different versions of the API, or if the API is extended by a particular client or server implementatoin.
Clients and servers should tolerate and ignore unknown elements. Neither the client nor the server should maintain unknown elements.
[[bibliography]]
: rest : Roy Fielding, "Representational State Transfer (REST)" [http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm www.ics.uci.edu]
: atompub : "The Atom Syndication Format" - [http://www.ietf.org/rfc/rfc4287.txt ietf.org]
: comet : "A Standards Based Approach to Comet Communication with REST" [http://cometdaily.com/2008/01/17/proposal-for-native-comet-support-for-browsers/ cometdaily.com]
: rfc2119 : "Key words for use in RFCs to Indicate Requirement Levels" - [http://tools.ietf.org/html/rfc2119 ietf.org]
: rfc2616 : "HTTP/1.1 Protocol Parameters" - http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html w3.org]
[[/bibliography]]