2013-08-26 42 views
6

Queue giới thiệu dài ...Web dựa trên Chấp nhận tiêu đề

Tôi đã một nguồn tài nguyên quy định tại

http://my-awesome-product.com/api/widgets/3 

đại diện cho một widget với một id của 3. Trong Web API tôi sẽ xác định một bộ điều khiển để phục vụ tài nguyên đó như sau:

public class WidgetsController : ApiController 
{ 
    public Widget Get(int id) 
    { 
     return new Widget(...); 
    } 
} 

Bây giờ, lớp Widget có khả năng có thể là khá lớn, và muốn tiết kiệm băng thông từ cơ sở dữ liệu đến máy chủ web và từ máy chủ web đến máy khách, tôi tạo một số lớp DTO chứa một số trường bị hạn chế trong tổng số Widget tổng thể. Ví dụ:

public class WidgetSummary 
{ 
    public int Id { get; set; } 
    public string Code { get; set; } 
    public string Description { get; set; } 
    public decimal Price { get; set; } 
} 

public class FullWidgetForEditing 
{ 
    public int Id { get; set; } 
    public string Code { get; set; } 
    public string Description { get; set; } 
    public decimal Weight { get; set; } 
    public decimal Price { get; set; } 
    public Color Color { get; set; } 
    public decimal Width { get; set; } 
    public decimal Height { get; set; } 
    public decimal Depth { get; set; } 
} 

public class WidgetForDropDownList 
{ 
    public int Id { get; set; } 
    public string Code { get; set; } 
} 

Với những Widget cơ quan đại diện, khách hàng sẽ yêu cầu WidgetSummary để hiển thị trên một mạng lưới tóm tắt tất cả các Widget s trong hệ thống, nó sẽ yêu cầu FullWidgetForEditing trên trang chỉnh sửa của một cụ Widget, và nó sẽ yêu cầu WidgetForDropDownList để sử dụng trong danh sách thả xuống trên mẫu đơn đặt hàng.

Từ những gì tôi hiểu về REST, để truy cập vào một Widget cần có một URL duy nhất vì nó là một nguồn tài nguyên duy nhất, bất kể đại diện của mình và khách hàng nên xác định Accept tiêu đề với một số loại phương tiện truyền thông để lấy Widget trong của nó các dạng khác nhau, ví dụ my-awesome-product.type=widgetsummary, my-awesome-product.type=fullwidgetforeditingmy-awesome-product.type=widgetfordropdownlist.

tôi có thể đạt được điều đó trong Web API bằng cách kiểm tra các tiêu đề của các yêu cầu như vậy:

public class WidgetsController : ApiController 
{ 
    public object Get(int id) 
    { 
     if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "widgetsummary"))) 
     { 
      return new WidgetSummary(...); 
     } 
     else if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "fullwidgetforediting"))) 
     { 
      return new FullWidgetForEditing(...); 
     } 
     else if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "widgetfordropdownlist"))) 
     { 
      return new WidgetForDropDownList(...); 
     } 

     throw new HttpResponseException(HttpStatusCode.NotAcceptable); 
    } 
} 

Tuy nhiên, điều này trở nên lộn xộn một cách nhanh chóng như số lượng các loại phát triển và làm cho kiểm tra đơn vị khó khăn hơn. Những gì tôi thực sự muốn làm là như sau:

public class WidgetsController : ApiController 
{ 
    [HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "widgetsummary")] 
    public WidgetSummary GetWidgetSummary(int id) 
    { 
     return new WidgetSummary(); 
    } 

    [HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "fullwidgetforediting")] 
    public FullWidgetForEditing GetFullWidgetForEditing(int id) 
    { 
     return new FullWidgetForEditing(); 
    } 

    [HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "widgetfordropdownlist")] 
    public WidgetForDropDownList GetWidgetForDropDownList(int id) 
    { 
     return new WidgetForDropDownList(); 
    } 
} 

Và có đường dẫn API Web đến phương pháp hành động cụ thể dựa trên loại phương tiện. Tuy nhiên, tôi đã điều tra trọng số ApiControllerActionSelector, tôi bắt đầu kéo một lượng lớn mã hiện có cho thuộc tính này bởi vì tôi thực sự muốn lựa chọn hành động mặc định, nhưng trong trường hợp các hành động mơ hồ, tôi muốn lọc danh sách các hành động dựa trên phương tiện kiểu. Tôi thực sự muốn nó không xâm nhập để tôi có thể trộn quy ước định tuyến, định tuyến thuộc tính tiêu chuẩn (trong API Web v2) và thuộc tính giả định này định tuyến trong cùng một bộ điều khiển nếu cần.

Thời gian câu hỏi: hiện tại, bạn có thể triển khai chiến lược định tuyến như vậy với API Web không? Tôi có phải hoàn toàn reimplement các ApiControllerActionSelector để đạt được điều này (và sau đó hãy chắc chắn reimplementation của tôi vẫn được cập nhật)?

+0

flipchart, tôi cũng đang tìm kiếm chính xác những gì bạn mô tả - một URL nên đại diện cho 1 đối tượng (không định dạng của nó, hoặc trả lại loại). Bạn đã bao giờ tìm được giải pháp chưa? Tôi bối rối là lý do tại sao việc ghi đè bộ chọn mặc định đã lấy quá nhiều mã, bạn không nên xử lý các tiêu đề chấp nhận của mình và nếu bạn không nhận được kết quả phù hợp, hãy chuyển yêu cầu xuống lớp cơ sở? Tôi đang thiếu gì? – jeremyh

Trả lời

2

Vì vậy, đây là câu hỏi bạn cần phải suy ngẫm. Có thực sự ba đại diện, hoặc là ba nguồn tài nguyên khác biệt? Nếu bạn quyết định lưu trữ các biểu diễn đó, URI có đủ để xác định biểu diễn được lưu trong bộ nhớ cache hay bạn cũng cần phải thay đổi trên tiêu đề chấp nhận không?

Nếu bạn chấp nhận rằng chúng đủ khác nhau để trở thành tài nguyên thì chúng phải được xác định bằng các URL khác nhau. Nếu bạn quyết định sử dụng siêu liên kết trong câu trả lời của mình, bạn có muốn không trỏ đến 'widgetsummary' độc lập với 'widgeteditform' không?

Thường cần có nhiều lần biểu diễn khi bạn muốn hỗ trợ các thiết bị khách khác nhau chỉ có khả năng hỗ trợ một số loại phương tiện nhất định. ví dụ. Thiết bị A nhận được Rep1 và thiết bị B được Rep2. Rất hiếm khi bạn muốn Thiết bị A truy cập cả Thiết bị A và Rep1 và Rep2.

Chỉ cần suy nghĩ của tôi ...

+0

Về chính câu hỏi, có, bạn đã đúng. Nói chung, các điểm lật cho một chủ đề thú vị là phiên bản API và định tuyến với MediaTypes hoặc X-MediaTypes ... – Mauro

Các vấn đề liên quan