Nancy + rest mow2012
-
Upload
christian-horsdal -
Category
Technology
-
view
1.955 -
download
0
description
Transcript of Nancy + rest mow2012
![Page 1: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/1.jpg)
Click to edit Master title style
• Click to edit Master text styles– Second level• Third level
– Fourth level» Fifth level
19-04-2012 1
The Lightweight Approach to Building Web Based APIs with .NET
MOW 2012
![Page 2: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/2.jpg)
Who Am I?
What is “lightweight”
RestBucks
REST
Nancy
Agenda
![Page 3: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/3.jpg)
3
What is lightweight?
![Page 4: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/4.jpg)
4
Low ceremony
Low cruft
Conventions
What is lightweight?
![Page 5: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/5.jpg)
5
Open
Agile
Inexpensive
What is lightweight?
![Page 6: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/6.jpg)
6
Restbucks
![Page 7: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/7.jpg)
7
REST
![Page 8: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/8.jpg)
8
Level 3: Hypermedia
Level 2: HTTP Verbs
Level 1: Resources
Level 0: POX-RPC
REST – Richardsons Maturity Model
![Page 9: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/9.jpg)
9
The basic building blocks of web API
Anything with a URI
http://restbucks.com/menu/
http://restbucks.com/orders/
http://restbucks.com/order/42/
http://restbucks.com/order/42/payment/
REST - Resources
![Page 10: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/10.jpg)
10
REST- Representations
GET http://restbucks.com/order/19202048/ HTTP/1.1
Accept: application/vnd.restbucks+xml
<?xml version="1.0"?><order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://restbuckson.net"> <links> <link uri="http://restbucks.com/order/19202048" rel="http://restbucks.com/docs/order-get.htm" mediaType="application/vnd.restbucks+xml" /> <link uri="http://restbucks.com/order/19202048" rel="http://restbucks.com/docs/order-update.htm" mediaType="application/vnd.restbucks+xml" /> <link uri="http://restbucks.com/order/19202048" rel="http://restbucks.com/docs/order-cancel.htm" mediaType="application/vnd.restbucks+xml" /> <link uri="http://restbucks.com/order/19202048/payment" rel="http://restbucks.com/docs/order-pay.htm" mediaType="application/vnd.restbucks+xml" /> </links> <location>inShop</location> <cost>7.60000</cost> <items> <item> <name>Latte</name> <quantity>1</quantity> <milk>skim</milk> <size>large</size> </item> </items> <status>unpaid</status></order>
![Page 11: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/11.jpg)
11
REST - Representations
GET http://restbucks.com/order/19202048/ HTTP/1.1
Accept: application/vnd.restbucks+json
{ "Location":inShop, "Cost":7.60000, "Items":[ { "Name":"Latte", "Quantity":1, "Preferences":{ "milk":"skim", "size":"large" } } ], "Status":1, "Links":[ { "Uri":"http://restbucks.com/order/19202048", "Relation":"http://restbucks.com/docs/order-get.htm", "MediaType":"application/vnd.restbucks+xml" }, { "Uri":"http://restbucks.com/order/19202048", "Relation":"http://restbucks.com/docs/order-update.htm", "MediaType":"application/vnd.restbucks+xml" }, { "Uri":"http://restbucks.com/order/19202048", "Relation":"http://restbucks.com/docs/order-cancel.htm", "MediaType":"application/vnd.restbucks+xml" }, { "Uri":"http://restbucks.com/order/19202048/payment", "Relation":"http://restbucks.com/docs/order-pay.htm", "MediaType":"application/vnd.restbucks+xml" } ]}
![Page 12: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/12.jpg)
12
GET
POST
PUT
DELETE
HEAD
OPTIONS
PATCH
REST - verbs
![Page 13: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/13.jpg)
13
Accept
Content-Type
If-None-Match
Etag
REST - Headers
![Page 14: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/14.jpg)
14
![Page 15: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/15.jpg)
15
“Close” to http
Very, very readable code
Very explicit routing
Embraces modularity
Embraces IoC/DI
Embraces testing
Runs anywhere
Why Nancy?
![Page 16: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/16.jpg)
Organizes your routes
Nancy Basics
public class MainModule : NancyModule { public MainModule() { Get["/"] = _ => "Hello from root"; } }
public class SubModule : NancyModule { public SubModule() : base("subpath") { Get["/"] = _ => "Hello from subpath"; } }
![Page 17: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/17.jpg)
Defines which verbs you accepts
HEAD and OPTIONS and automatic
Nancy Basics
public class MainModule : NancyModule { public MainModule() { Get["/"] = _ => "Hello from root"; Post["/”] = _ => DoPost(Request.Form.my_value) Delete["/{id}”] = p => Delete(p.id); Put["/”] = _ => DoPut(Request.Body); Patch["/”] = _ => DoPatch(Request.Body); } }
![Page 18: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/18.jpg)
18
Restbuck on Nancy – Place an Order
public OrdersResourceHandler(IRepository<Product> productRepository, IRepository<Order> orderRepository) : base("/orders"){ this.productRepository = productRepository; this.orderRepository = orderRepository;
Post["/"] = _ => HandlePost(this.Bind<OrderRepresentation>());}
private Response HandlePost(OrderRepresentation orderRepresentation){ var order = TryBuildOrder(orderRepresentation); if (!order.IsValid()) return InvalidOrderResponse(order);
orderRepository.MakePersistent(order); return Created(order);}
![Page 19: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/19.jpg)
19
RestBucks on Nancy – View an Order
public OrderResourceHandler(IRepository<Order> orderRepository) : base(”/order”){ this.orderRepository = orderRepository; Get["/{orderId}/”] = parameters => GetHandler((int) parameters.orderId); …}
public Response GetHandler(int orderId){ var order = orderRepository.GetById(orderId); if (order == null) return HttpStatusCode.NotFound;
if (order.Status == OrderStatus.Canceled) return Response.MovedTo(new ResourceLinker(CanceledOrderUri(orderId);
if (Request.IsNotModified(order)) return Response.NotModified();
return Response.WithContent(Request.Headers.Accept, OrderRepresentationMapper.Map(order,Request.BaseUri())) .WithCacheHeaders(order);}
![Page 20: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/20.jpg)
20
RestBucks on Nancy – Cancel an Order
Delete["/{orderId}/"] = parameters => Cancel((int) parameters.orderId);
public Response Cancel(int orderId) { var order = orderRepository.GetById(orderId); if (order == null) return HttpStatusCode.NotFound;
order.Cancel("canceled from the rest interface"); return HttpStatusCode.NoContent; }
![Page 21: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/21.jpg)
21
RestBucks on Nancy –Pay an Order
Post["/{orderId}/payment"] = parameters => Pay((int) parameters.orderId, this.Bind<PaymentRepresentation>());
public Response Pay(int orderId, PaymentRepresentation paymentArgs) { var order = orderRepository.GetById(orderId); if (order == null) return HttpStatusCode.NotFound;
order.Pay(paymentArgs.CardNumber, paymentArgs.CardOwner); return HttpStatusCode.OK; }
![Page 22: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/22.jpg)
22
RestBucks on Nancy – XML or JSON
return Response.WithContent(Request.Headers.Accept, OrderRepresentationMapper.Map(order, Request.BaseUri())) .WithCacheHeaders(order);
public static Response WithContent<T>(this IResponseFormatter formatter, IEnumerable<Tuple<string, decimal>> acceptHeaders, T content) { var xmlWeight = CalculateWeightForContentType(acceptHeaders, "xml"); var jsonWeight = CalculateWeightForContentType(acceptHeaders, "json"); if (jsonWeight > xmlWeight) return formatter.AsJson(content); else return formatter.AsXml(content); }
![Page 23: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/23.jpg)
23
RestBucks on Nancy – Conditional Gets
return Response.WithContent(Request.Headers.Accept, OrderRepresentationMapper.Map(order, Request.BaseUri())) .WithCacheHeaders(order);
public static Response WithCacheHeaders(this Response response, IVersionable versionable, TimeSpan? maxAge = null){ return response.WithHeaders( new { Header = "ETag", Value = string.Format("\"{0}\"", versionable.Version) }, new { Header = "Cache-Control", Value = string.Format("max-age={0}, public", maxAge ?? TimeSpan.FromSeconds(10)) }); }
![Page 24: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/24.jpg)
24
RestBucks on Nancy – Conditional Gets
if (Request.IsNotModified(order)) return Response.NotModified();
public static bool IsNotModified(this Request request, IVersionable versionable) { if (!request.Headers.IfNoneMatch.Any()) return false; var etag = request.Headers.IfNoneMatch.First(); return string.Format("\"{0}\"", versionable.Version) == etag; }
public static Response NotModified(this IResponseFormatter formatter, TimeSpan? maxAge = null) { Response response = HttpStatusCode.NotModified;
return response.WithHeaders( new { Header = "ReasonPhrase", Value = "Not modified"}, new { Header = "Cache-Control", Value = string.Format("max-age={0}, public", maxAge ?? TimeSpan.FromSeconds(10)) }); }
![Page 25: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/25.jpg)
…
Nancy.Hosting
Nancy
Your Application
Nancy.Hosting
![Page 26: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/26.jpg)
Usage:> Install-Package Nancy.Hosting.*
Hosts:ASP.NET
WCF
Self
OWIN
Nancy.Hosting
![Page 27: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/27.jpg)
29
Nancy.Testing
[Test] public void WhenOrderHasNotChanged_ThenReturn304() { // Arrange var orderRepo = new RepositoryStub<Order>(new Order(1, 123); var app = new Browser( new ConfigurableBootstrapper (with => { with.Dependency<IRepository<Product>>(…); with.Dependency<IRepository<Order>>(orderRepository); } )); // Act var response = app.Get("/order/123/", with => { with.HttpRequest(); with.Header("If-None-Match", "\"1\""); }); //Assert response.StatusCode.Should().Be.EqualTo(HttpStatusCode.NotModified); }
![Page 28: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/28.jpg)
30
“Close” to http
Very, very readable code
Very explicit routing
Embraces modularity
Embraces IoC/DI
Embraces testing
Runs anywhere
Why Nancy?
![Page 29: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/29.jpg)
31
LightweightLow ceremony
Low cruft
Follows conventions
Open
Agile
Why REST + Nancy
![Page 30: Nancy + rest mow2012](https://reader033.fdocuments.in/reader033/viewer/2022061305/549f740eac795933768b49f2/html5/thumbnails/30.jpg)
32
Restbucks on Nancy: http://github.com/horsdal/Restbucks-on-Nancy
Rest in Practice: http://restinpractice.com/book.html
Nancy: www.nancyfx.org
Me:
Twitter: @chr_horsdal
Blog: horsdal.blogspot.com
email: [email protected]
More …