rest &.net james crisp.net practice lead thoughtworks australia
TRANSCRIPT
REST &
.NET
James Crisp.NET Practice Lead
ThoughtWorks Australia
James Crisp
The Web
*-ilities
Scalability
Recoverability & Reliability
Security
Discoverability
How to bring toWeb services?
Tunneling
RPC URLs
POX
SOAP & WS-*
REpresentational State Transfer
“REST contributes ... the rationale behind the modern Web's software architecture...”
-- Roy Fielding
Resourcese.g. Person, Car, Post
Representations
<person> <name>Bill Gates</name> <gender>m</gender></person>
Addressabilityhttp://mysite.com/people/joe_citizen
http://mysite.com/people/joe_citizen/friends
Uniform Interface
GET
POST
HEAD
PUT
DELETE
OPTIONS
Su
pp
ort
GET
GET /people/joe_citizen HTTP/1.1Host: mysite.comAccept: application/xml
Response200 OKContent-Type: application/xmlLast-Modified: 2008-1-1 15:00..
<person> <name>Joe Citizen</name> <age>42</age> <gender>m</gender></person>
HEADHEAD /people/joe_citizen HTTP/1.1Host: mysite.com
200 OKContent-Type: application/xmlLast-Modified: 2008-1-1 15:00..ETag: a32daf15-b33da2a4d
Response
POSTPOST /people HTTP/1.1Content-Type: text/xmlHost: mysite.com....<person> <name>Tina Jones</name> <age>25</age> <gender>F</gender></person>
Response
201 CREATEDLocation: /people/tina_jones
(optionally with body)
PUTPUT /people/tina_jones HTTP/1.1Content-Type: text/xmlHost: mysite.com....<person> <name>Tina Jones</name> <age>24</age> <gender>F</gender></person>
Response
200 OKLocation: /people/tina_jones
(optionally with body)
DELETEDELETE /people/joe_citizen HTTP/1.1Host: mysite.com
200 OKContent-Type: application/xml<admin:personDeleted> joe_citizen</admin:personDeleted>
Response
OPTIONS
OPTIONS /people HTTP/1.1Host: mysite.com
200 OKAllowed: GET,HEAD,POST
Response
Status Codes
2xx = All good200 – OK201 – Created
3xx = Redirect301 – Moved permanently307 – Temporary redirect304 – Not modified (ie, see cache)
4xx = Client error400 – Bad request401 – Unauthorized403 – Forbidden405 – Method not allowed409 – Conflict
5xx = Server error500 – Internal server error
Headers
Content-Type:text/htmlapplication/xmlimage/jpeg....
WWW-Authenticate:
Authorization:
Last-Modified:If-Modified-Since:
ETag:If-None-Match:
Location:
Describe your services?
URI Templateshttp://s3.amazon.com/{bucket-name}/{object-name}
http://mysite.com/users/{user-name}/photos
http://google.com/search?q={search-query}
Start URL + Links
https://bank.com/accounts/345095
<account> <name>Tina Jones</name> <link rel="history" href="/tjones/account_history"> <link rel="close" verb="delete" href="/tjones"></account>
Microformats<account> <name>Tina Jones</name> <link rel="transaction-search" href="account_history?
from={date-from}&to={date-to}">
</account>
State Management
http://google.com
Search
google.com/search?q=rest
google.com/search?q=rest&start=10
Next Page
Searching
Searched
More Results
Data Format?
XHTML<h1>Accounts</h1> <ul> <li> <a rel="account_details" href="/tjones">Tina Jones</a> </li>
<li>.....
JSON
{ "account_name": "Tina Jones", "links":
{"history": "/tjones/history"}}
<XML></XML>
Framework
Ordering Pizza
http://epizza.com
GET / HTTP/1.1Host: epizza.comContent-Type: application/xml
Response
200 OKLocation: http://epizza.comContent-Type: application/xmlContent-Length: ...
<epizza xmlns="/schema"> <message>Welcome!</message> <link rel="menu" href="/menu" /> <link rel="place-order" href="/orders" /><epizza>
Let's see the menu!
GET /menu HTTP/1.1Host: epizza.comContent-Type: application/xml
200 OKLocation: ...
<epizza xmlns="/schema"> <menu> <pizza name="pepperoni"> <ingredients>...</ingredients> </pizza> ... <menu> <link rel="place-order" href="/orders" /></epizza>
Menu Response
Ordering time!POST /orders HTTP/1.1Host: epizza.comContent-Type: application/xmlContent-Length: ...
<order xmlns="/schema"> <pizza name="pepperoni" /></order>
201 CreatedLocation: http://epizza.com/orders/413Content-Type: ...
<epizza xmlns="/schema"> <order> <pizza name="pepperoni" /> </order> <link rel="destination" href="/orders/413/address"></epizza>
Place Order Response
Beer with that?
OPTIONS /orders/413 HTTP/1.1Host: epizza.com
200 OKAllowed: GET, HEAD, POST, PUT
Add BeerPOST /orders/413 HTTP/1.1Host: epizza.comContent-Type: application/xmlContent-Length: ...
<order xmlns="/schema"> <drink name="corona" /></order>
200 OKLocation: http://epizza.com/orders/413Content-Type: ...
<epizza xmlns="/schema"> <order> <pizza name="pepperoni" /> <drink name="corona" /> </order> <link rel="destination" href="/orders/413/destination"></epizza>
Response
Destination AddressPUT /orders/413/address HTTP/1.1
Host: epizza.comContent-Type: application/xmlContent-Length: ...
<address xmlns="/schema"> <line1>35 Rue Rd</line1> <suburb>Potts Point</suburb></address>
Destination Response200 OKHost: epizza.comContent-Type: application/xmlContent-Length: ...
<address xmlns="/schema"> <line1>35 Rue Rd</line1> <suburb>Potts Point</suburb></address>
200 OKLocation: http://epizza.com/orders/413Content-Type: ...
<epizza xmlns="/schema"> <order> <pizza name="pepperoni" /> <drink name="corona" /> </order></epizza>
GET /orders/413
Can we?
OPTIONS /orders/413 HTTP/1.1Host: epizza.com
200 OKAllowed: GET, HEAD
Too late!
Back at theePizza
Kitchen..
GET /orders
Implementation
Clientvar request =
(HttpWebRequest) WebRequest.Create(URL);
request.Methodrequest.ContentTyperequest.GetRequestStream()
var response = (HttpWebResponse)request.GetResponse();
response.StatusCoderesponse.Headersresponse.GetResponseStream()
Server
IHttpHandlerpublic class RestHandler : IHttpHandler{ public void ProcessRequest(HttpContext context) { context.Response.ContentType =
"application/xml"; if (context.Request.HttpMethod == "GET") { context.Response.Write("<xml>...</xml>"); }}
WCF REST
[ServiceContract]public interface IPizzaService{
[WebGet(UriTemplate="/orders/{orderId}")][OperationContract]Order GetOrder(int orderId);
}
Status codes?
Headers?
Links?
Microformats?
ASP.NET MVC
Routing Table
Controller Method
Model View
RoutesIn GlobalApplication : HttpApplication
void RegisterRoutes(RouteCollection routes) { routes.MapRoute( "AddToOrder", "orders/{id}", new { controller = "Orders", action = "AddToOrder" }, new { httpMethod = new HttpMethodConstraint("POST")});
... }
Controllerpublic class OrdersController : Controller{ public ActionResult AddToOrder(int id) { var order = Order.Load(id); var itemToAdd = CreateMenuItemFromRequest(); order.Items.Add(itemToAdd); order.Save();
// response.StatusCode = 200;
return View(order); }}
Model
public class Order{ public MenuItem[] Items { get { ... }; }
public Address DeliveryAddress { get; set; }}
View
<%@ Page Language="C#" ...>
<epizza xmlns="/schema"> <order> <% foreach (var item in Order.Items) { %> <pizza name= "<%= item.Name %>" /> <% } %> </order> <% if (Order.DeliveryAddress == null) { %> <link rel="destination" href= ...</epizza>
MVC REST
Wrinkles
See also...Slides & Code
http://www.jamescrisp.org MVC http://www.asp.net/mvc/
RESTful Web Services
http://flickr.com/photos/misserion/2190827125/ - webhttp://flickr.com/photos/hyougushi/412600118/ - bridgehttp://en.wikipedia.org/wiki/Image:Internet_map_1024.jpg - webhttp://flickr.com/photos/gradin/3361527/ - defibrillatorhttp://flickr.com/photos/keoki/1418303458/ - padlockshttp://roadmap.cbdiforum.com/reports/protocols/ - ws* stackhttp://flickr.com/photos/chainsawpanda/1528894/ - tunnelhttp://flickr.com/photos/psd/421186578/ - fieldinghttp://flickr.com/photos/esparta/187132368/ - bill gateshttp://flickr.com/photos/acme_explosives/117276632/ - network plugshttp://flickr.com/photos/walterhertman/101489766/ - speedometershttp://flickr.com/photos/sis/5908199/ - Petco explosionhttp://flickr.com/photos/pleasewait/476776136/ - letterhttp://flickr.com/photos/bigpinkcookie/108895725/ - Eiffel towerhttp://flickr.com/photos/bala_/2077047513/ - pizza restauranthttp://flickr.com/photos/57231735@N00/201482385/ - pepperoni pizzahttp://flickr.com/photos/sheeshoo/10321250/ - coronahttp://flickr.com/photos/freddy/39340695/ - saladhttp://flickr.com/photos/huthfamily/1304336305/ - 42 pizza boxeshttp://www.crummy.com/writing/RESTful-Web-Services/cover.png – REST book
Image References
Questions?