2011-10-14 51 views
7

Tôi đang tạo API REST và tôi đã chơi với ý tưởng cho phép nhóm các yêu cầu từ khách hàng. Bằng cách nhóm, tôi có nghĩa là họ có thể gửi một yêu cầu, chứa nhiều yêu cầu "thực" và chúng được gửi đến khách hàng cùng nhau. Thông thường yêu cầu ajax javascript. Một cái gì đó như thế này:Yêu cầu API gộp

POST /bundlerequest 

["/person/3243", "/person/3243/friends", "/comments/3243?pagesize=10&page=1", "/products", "/product/categories" ] 

(Yêu cầu kèm chỉ có thể yêu cầu GET, tính đến nay ít nhất) này được thiết kế để trở lại một cái gì đó như thế này

{ 
    "success" : ["/person/3243", "/person/3243/friends", "/comments/3243?pagesize=10&page=1", "/products", "/product/categories" ], 
    "error" : [], 
    "completiontime" : 94, 
    other relevant metadata... 
    "responses" : [ 
     {"key" : "/person/3243" , "data" : {"name" : "John", ...} }, 
     {"key" : "/person/3243/friends" , "data" : [{"name": "Peter", "commonfriends" : 5, ...}] }, 
     etc... 
    ] 
} 

Những lợi ích của bó này là nó làm giảm số lượng yêu cầu và điều đó đặc biệt quan trọng trên thiết bị di động chẳng hạn.

Câu hỏi đầu tiên của tôi là, cách tiếp cận của tôi là tốt nhất? Có ai có kinh nghiệm làm việc như thế này không?

AFAIK cách phổ biến để giải quyết điều này là viết mã phía máy chủ để trả về dữ liệu kết hợp, mà tôi tin là có liên quan cho (các) khách hàng. (Ví dụ, luồng người dùng twitter thực hiện điều này, kết hợp thông tin người, tin nhắn mới nhất, tin nhắn cá nhân mới nhất, v.v.) Nhưng điều này làm cho API rất quan tâm và khi khách hàng cần thay đổi, máy chủ có thể cần thay đổi để chứa tối ưu.

Và câu hỏi thứ hai là cách triển khai điều này?

Phần cuối của tôi là ASP.NET MVC 3 và IIS 7. Tôi có nên triển khai nó trong ứng dụng, có hành động bundlerequest gọi nội bộ các hành động khác được chỉ định trong yêu cầu không?

Có thể triển khai trực tiếp trong IIS 7 không? Viết một mô-đun minh bạch chặn các yêu cầu đến/bundlerequest và sau đó gọi tất cả các yêu cầu phụ tương ứng, làm cho ứng dụng hoàn toàn không biết về gói xảy ra? Điều này cũng sẽ cho phép tôi thực hiện điều này theo cách ứng dụng bất khả tri.

+0

Điều này nghe có vẻ như một ý tưởng hay. –

+0

Có phải tất cả các url đó đều chỉ trả về JSON không? Hoặc một số có thể trả lại phần nội dung HTML và các nội dung khác? –

+0

@DarinDimitrov chỉ có JSON, tuy nhiên tôi thấy các vấn đề tiềm năng với người dùng bị đăng xuất hoặc không có quyền truy cập vào các phần của API chẳng hạn, và sau đó có thể chuyển hướng đến trang đăng nhập. Đây là những vấn đề tôi sẽ phải giải quyết. –

Trả lời

3

Bạn có thể sử dụng một asynchronous controller để tổng hợp những yêu cầu trên máy chủ. Chúng ta hãy bắt đầu đầu tiên bằng cách định nghĩa một mô hình điểm cho rằng sẽ được trả lại bởi bộ điều khiển:

public class BundleRequest 
{ 
    public string[] Urls { get; set; } 
} 

public class BundleResponse 
{ 
    public IList<string> Success { get; set; } 
    public IList<string> Error { get; set; } 
    public IList<Response> Responses { get; set; } 
} 

public class Response 
{ 
    public string Key { get; set; } 
    public object Data { get; set; } 
} 

sau đó bộ điều khiển:

public class BundleController : AsyncController 
{ 
    public void IndexAsync(BundleRequest request) 
    { 
     AsyncManager.OutstandingOperations.Increment(); 
     var tasks = request.Urls.Select(url => 
     { 
      var r = WebRequest.Create(url); 
      return Task.Factory.FromAsync<WebResponse>(r.BeginGetResponse, r.EndGetResponse, url); 
     }).ToArray(); 

     Task.Factory.ContinueWhenAll(tasks, completedTasks => 
     { 
      var bundleResponse = new BundleResponse 
      { 
       Success = new List<string>(), 
       Error = new List<string>(), 
       Responses = new List<Response>() 
      }; 
      foreach (var task in completedTasks) 
      { 
       var url = task.AsyncState as string; 
       if (task.Exception == null) 
       { 
        using (var response = task.Result) 
        using (var stream = response.GetResponseStream()) 
        using (var reader = new StreamReader(stream)) 
        { 
         bundleResponse.Success.Add(url); 
         bundleResponse.Responses.Add(new Response 
         { 
          Key = url, 
          Data = new JavaScriptSerializer().DeserializeObject(reader.ReadToEnd()) 
         }); 
        } 
       } 
       else 
       { 
        bundleResponse.Error.Add(url); 
       } 
      } 
      AsyncManager.Parameters["response"] = bundleResponse; 
      AsyncManager.OutstandingOperations.Decrement(); 
     }); 
    } 

    public ActionResult IndexCompleted(BundleResponse response) 
    { 
     return Json(response, JsonRequestBehavior.AllowGet); 
    } 
} 

và bây giờ chúng ta có thể gọi nó:

var urls = [ 
    '@Url.Action("index", "person", new { id = 3243 }, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("friends", "person", new { id = 3243 }, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("index", "comments", new { id = 3243, pagesize = 10, page = 1 }, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("index", "products", null, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("categories", "product", null, Request.Url.Scheme, Request.Url.Host)' 
]; 
$.ajax({ 
    url: '@Url.Action("Index", "Bundle")', 
    type: 'POST', 
    contentType: 'application/json; charset=utf-8', 
    data: JSON.stringify(urls), 
    success: function(bundleResponse) { 
     // TODO: do something with the response 
    } 
}); 

Dĩ nhiên một số tinh chỉnh có thể là cần thiết để thích ứng với nhu cầu cụ thể của bạn. Ví dụ bạn đã đề cập gửi yêu cầu AJAX với phiên hết hạn có thể chuyển hướng đến trang Đăng nhập và do đó không thu được lỗi. Đó thực sự là một PITA trong ASP.NET. Phil Haack blogged một cách có thể để phá vỡ hành vi không mong muốn này theo cách RESTful. Bạn chỉ cần thêm tiêu đề tùy chỉnh vào yêu cầu.

+0

Cảm ơn bạn đã trả lời rất chi tiết và cũng chỉ cho tôi đúng hướng để giải quyết vấn đề xác thực biểu mẫu. Có vẻ như những gì tôi cần. Tôi sẽ căn cứ triển khai của tôi về điều này và xem nó phù hợp như thế nào với ứng dụng của tôi. –