Recently I was doing a review of some .NET 3.5 WCF REST code based on the REST Starter Kit to see what it would take to move it to .NET 4.
The more I looked at the code and thought about it deeply I realized that the mechanics of exposing a service over HTTP are not the hard part. What is difficult is to get the semantics of HTTP right. After spending some time reading through the HTTP spec I took a stab at creating the Canonical REST Entity Service
“ca%u00b7non%u00b7i%u00b7cal [ k%u0259 n%u00f3nnik’l ] conforming to general principles: conforming to accepted principles or standard practice’”
What I was after was a set of requirements that I could verify about the way in which a REST Entity Service should behave. Here is what I came up with.
First of all I learned that Canonical is spelled with 1 n and not two as in “Cannonical” [sic] which I used all over the place in this code so sorry.
Watch
Download
Canonical REST Service (MSDN Code Gallery)
Canonical REST Entity Service URI Map
Base URI: http://tempuri.org/Resource where Resource is the name of the REST collection (i.e. Customers, Orders etc.)
Web Formats XML and JSON are supported for all request/response messages
URI Template | HTTP Method | Description | Status | Response Content | Response Contains |
---|---|---|---|---|---|
/{key} | GET | Gets a resource by key | 200 | OK | Serialized resource |
304 | Not Modified | Empty | |||
400 | Bad Request | Empty or Serialized error message | |||
404 | Not Found | Empty | |||
/?skip={skip}&take={take} | GET | Gets a list of resources starting with skip+1 and returning take | 200 | OK | Serialized resources |
400 | Bad Request | Empty or Serialized error message | |||
/ | POST | Adds a resource to the collection | 200 | OK | Serialized resource |
204 | No Content | Empty | |||
400 | Bad Request | Empty or Serialized error message | |||
409 | Conflict | Empty or Serialized error message | |||
/{key} | PUT | Adds or Updates a resource identified by {key}. Some services might not allow add with PUT. If you return the updated resource, return 200. If you don’t return 204. | 200 | OK | Updated resource |
204 | No Content | Empty | |||
400 | Bad Request | Empty or Serialized error message | |||
404 | Not Found | Empty or Serialized error message | |||
409 | Conflict | Empty or Serialized error message | |||
/{key} | DELETE | Removes the resource identified by {key}. If you return the resource removed, return 200. If you don’t return 204. | 200 | OK | Deleted Resource |
204 | No Content | Empty | |||
400 | Bad Request | Empty or Serialized error message | |||
404 | Not Found | Empty or Serialized error message | |||
409 | Conflict | Empty or Serialized error message |
GET TESTS
GET Spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Tests GET /{key}
- GET MUST return a resource given a key if the resource with that key exists
- GET MUST return 400-BadRequest if the key is invalid
- GET MUST return 404-NotFound if the key is not found
- GET MUST return 304-NotModified if Conditional GET conditions are met using If-None-Match
- GET SHOULD return an ETag header
Tests GET /?skip={skip}&take={take}
- GET MUST skip {skip} resources in the collection and return up to {take} resources.
- GET MUST return resources starting with the first one when {skip} is not defined
- GET MUST return zero resources when {skip} is greater than the number of resources in the collection
- GET MUST return 400-BadRequest if {skip} is < 0
- GET MUST return zero or more resources when {take} is not provided
- GET MUST return 400-BadRequest if {take} is < 0
POST TESTS
POST Spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Tests POST /
- POST MUST append a valid resource to the resource collection using a server generated key and return 201 – Created with a location header, entity tag and entity body
- POST MUST return 400-Bad Request if the entity is invalid
- POST MUST return 409-Conflict if the entity conflicts with another entity
- POST MUST ignore writes to entity fields the server considers read only
PUT TESTS
PUT Spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Tests PUT /{key}
- PUT MUST Update the entity identified by the URI if it exists and return 200-OK with the modified entity and etag header
- PUT MAY Add a new entity using the key provided in the URI and return 201-Created with entity location and etag
- PUT MUST respect the Precondition If-Match
- PUT MUST be Idempotent
- PUT MUST NOT alter the key of the entity so that it does not match the key of the URI
- PUT MUST return 400-BadRequest if the entity is invalid
- PUT MUST return 400-BadRequest if the key is invalid
- PUT MUST ignore writes to entity fields the server considers read only
- PUT MUST return 404-NotFound if the server does not allow new entities to be added with PUT
DELETE TESTS
DELETE Spec http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Tests DELETE /{key}
- DELETE SHOULD delete an entity that exists and return 200-OK with the deleted entity or 204-No Content if the response does not include the entity
- DELETE SHOULD be idempotent
- DELETE SHOULD return with 412-PreconditionFailed if no matching entity for If-Match etag
- DELETE SHOULD succeed if matching entity for If-Match etag
- DELETE SHOULD succeed if wildcard used in If-Match etag
- DELETE SHOULD return 202-Accepted if the request to delete has not been enacted
- DELETE SHOULD return 400-BadRequest if the key is invalid