2013-04-18 40 views
11

Tôi đang cố gắng thiết kế một API web RESTful cho dịch vụ của chúng tôi bằng ASP.NET Web API. Tôi đang gặp rắc rối với việc tìm ra cách để định tuyến các hành động không CRUD đến hành động điều khiển thích hợp. Giả sử tài nguyên của tôi là một cánh cửa. Tôi có thể làm tất cả những thứ CRUD quen thuộc với cánh cửa của tôi. Hãy nói rằng mô hình cho cửa của tôi là:Cách định tuyến các hành động không phải CRUD trong một API Web RESTful ASP.NET?

public class Door 
{ 
    public long Id { get; set; } 
    public string InsideRoomName { get; set; } 
    public string OutsideRoomName { get; set; } 
} 

tôi có thể làm tất cả các hoạt động CRUD tiêu chuẩn của tôi qua api web của tôi:

POST: http://api.contoso.com/v1/doors 
GET: http://api.contoso.com/v1/doors 
GET: http://api.contoso.com/v1/doors/1234 
GET: http://api.contoso.com/v1/doors?InsideRoomName=Cafeteria 
PUT: http://api.contoso.com/v1/doors/1234 
DELETE: http://api.contoso.com/v1/doors/1234 

và vân vân. Nơi tôi gặp rắc rối là khi tôi cần phải mô hình hóa các hành động không phải CRUD chống lại cánh cửa của tôi. Tôi muốn mô hình hóa một động từ Khóa và Mở khóa đối với tài nguyên của mình. Đọc qua ASP.NET articles hướng dẫn có vẻ là chuyển sang cuộc gọi kiểu RPC khi sử dụng các tác vụ tùy chỉnh. Điều này mang lại cho tôi một con đường:

PUT: http://api.contoso.com/v1/doors/1234/lock 
PUT: http://api.contoso.com/v1/doors/1234/unlock 

Điều này có vẻ mâu thuẫn với tinh thần của REST nhằm mục đích cho đường dẫn chỉ ra tài nguyên. Tôi cho rằng tôi có thể mô hình động từ như một nguồn lực:

POST: http://api.contoso.com/v1/doors/1234/lockrequests 
POST: http://api.contoso.com/v1/doors/1234/unlockrequests 

Trong trường hợp này, tôi vẫn có thể sử dụng khuyên {controller}/{id}/{action} nhưng nó có vẻ như tôi vẫn đang tạo ra một hỗn hợp RPC/REST API. Có thể, hoặc thậm chí được đề xuất như xa như giao diện REST đi, để đặt các hành động tùy chỉnh trong danh sách các thông số?

PUT: http://api.contoso.com/v1/doors/1234?lock 
PUT: http://api.contoso.com/v1/doors/1234?unlock 

tôi có thể thấy trước một nhu cầu để có cuộc gọi này được hỗ trợ với các tham số truy vấn là tốt, chẳng hạn như:

PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria 

Làm thế nào tôi sẽ tạo ra con đường để lập bản đồ yêu cầu này để DoorsController của tôi?

public class DoorsController : ApiController 
{ 
    public IEnumerable<Doord> Get(); 
    public Door Get(long id); 
    public void Put(long id, Door door); 
    public void Post(Door door); 
    public void Delete(long id); 

    public void Lock(long id); 
    public void Unlock(long id); 
    public void Lock(string InsideRoomName); 
} 

tôi có thể làm cho một số giả định sai ở đây liên quan đến những gì được và không phải là thông lệ tốt nhất liên quan đến thiết kế REST API, vì vậy bất kỳ hướng dẫn có được đánh giá là tốt.

+0

Google sử dụng API REST với Blogger, kiến ​​nó sử dụng các hành động trong REST! https://developers.google.com/blogger/docs/3.0/reference/posts/publish – padibro

Trả lời

6

Để xử lý kịch bản lock/unlock bạn có thể cân nhắc việc thêm một tài sản State đến Door đối tượng:

public State State { get; set; } 

mà Nhà nước là một enum các giá trị có sẵn, ví dụ

{ 
LockedFromOutsideRoom, 
LockedFromInsideRoom, 
Open 
} 

Để làm rõ: Bạn đang thêm trạng thái cho đối tượng không chống lại các nguyên tắc an toàn khi trạng thái được chuyển qua api mỗi khi bạn gọi điện để thực hiện điều gì đó với Cửa.

Sau đó, qua api, bạn sẽ gửi yêu cầu PUT/POST để thay đổi trạng thái Cửa trên mỗi khóa/mở khóa. Bài đăng có lẽ sẽ tốt hơn vì chỉ có một thuộc tính được cập nhật:

POST: http://api.contoso.com/v1/doors/1234/state 
body: {"State":"LockedFromInsideRoom"} 
+0

Tôi có cần phải đăng ký tuyến đường tùy chỉnh cho điều này trong WebApiConfig.cs không? Dường như điều này vẫn theo mô hình của {controller}/{id}/{action}, nơi bộ điều khiển của tôi bây giờ sẽ có một DoorsController :: State (id dài, trạng thái trạng thái); phương pháp. – JadeMason

+1

@JadeMason - tuyến đường này sẽ hoạt động tốt –

+0

@ JoannaTurban câu trả lời hay! Tôi thậm chí sẽ làm điều đó với PUT, như thế này: 'PUT: http://api.contoso.com/v1/doors/1234 nội dung: {" State ":" LockedFromInsideRoom "}' bởi vì, bạn thực sự * cập nhật * tiểu bang. Ngoài ra, cảm thấy phù hợp hơn với [idempotence] của PUT (http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods_and_web_applications): Mỗi khi URL này được yêu cầu sẽ tạo ra kết quả tương tự. –

1

Từ phối cảnh REST bạn có thể muốn coi khóa là tài nguyên trong và của chính nó. Bằng cách này bạn tạo và xóa khóa độc lập với cánh cửa (mặc dù có lẽ là xác định vị trí điểm cuối khóa từ biểu diễn cửa).URL của tài nguyên có lẽ sẽ liên quan đến URL của cánh cửa, tuy nhiên từ góc nhìn RESTful, điều này là không liên quan. REST là về mối quan hệ giữa các tài nguyên, do đó, phần quan trọng là url của khóa có thể phát hiện được từ biểu diễn của cánh cửa.

2

Từ nguyên tắc RESTful, có thể tốt nhất là nên giới thiệu thuộc tính 'trạng thái' để quản lý các hành động không phải của CURD đó. Nhưng tôi không nghĩ nó đáp ứng được sự phát triển sản xuất thực sự.

Mọi câu trả lời cho loại câu hỏi này, có vẻ như bạn phải sử dụng một công việc xung quanh để thực thi thiết kế API của bạn đáp ứng RESTful. Nhưng mối quan tâm của tôi là, điều đó thực sự tạo thuận lợi cho cả người dùng và nhà phát triển?

chúng ta hãy xem thiết kế API3.0 của Google bloger: https://developers.google.com/blogger/docs/3.0/reference, nó đang sử dụng URL nhiều cho các hành động không phải của CURD.

Và đây là thú vị,

POST /blogs/blogId/posts/postId/comments/commentId/spam 

và mô tả là

Đánh dấu một bình luận là thư rác. Điều này sẽ đặt trạng thái của nhận xét thành spam và ẩn trạng thái đó trong hiển thị nhận xét mặc định.

Bạn có thể thấy, nhận xét có trạng thái cho biết đó có phải là spam hay không, nhưng nó không được thiết kế giống như câu trả lời được đề cập ở trên bởi JoannaTurban.

Tôi nghĩ từ quan điểm của người dùng, nó thuận tiện hơn. Không cần phải quan tâm đến cấu trúc và giá trị enum của "trạng thái". Và trên thực tế, bạn có thể đặt nhiều thuộc tính vào định nghĩa "trạng thái", như "isItSpam", "isItReplied", "isItPublic" vv. Thiết kế sẽ trở nên không thân thiện nếu trạng thái có nhiều thứ. Trên một số yêu cầu logic nghiệp vụ, để sử dụng một động từ dễ hiểu, thay vì cố gắng làm cho nó hoàn toàn là "thực sự" RESTful, nó hiệu quả hơn, cho cả người dùng lẫn nhà phát triển. Đây là ý kiến ​​của tôi.

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