THIẾT KẾ API REST - Nhận tài nguyên thông qua REST với các tham số khác nhau nhưng cùng một mẫu url


92

Tôi có một câu hỏi liên quan đến thiết kế url REST. Tôi đã tìm thấy một số bài đăng có liên quan ở đây: Các đại diện RESTful khác nhau của cùng một tài nguyên và tại đây: RESTful url để GET tài nguyên theo các trường khác nhau nhưng các phản hồi không hoàn toàn rõ ràng về các phương pháp hay nhất là gì và tại sao. Đây là một ví dụ.

Tôi có các url REST để đại diện cho tài nguyên "người dùng". Tôi có thể NHẬN người dùng có id hoặc địa chỉ email nhưng cách trình bày URL vẫn giống nhau cho cả hai. Xem qua rất nhiều blog và sách, tôi thấy rằng mọi người đã và đang làm điều này theo nhiều cách khác nhau. Ví dụ

đọc thực hành này trong một cuốn sách và ở đâu đó trên stackoverflow (dường như tôi không thể tìm thấy liên kết lại)

GET /users/id={id}
GET /users/email={email}

đọc thực hành này trên nhiều blog

GET /users/{id}
GET /users/email/{email}

Tham số truy vấn thường được sử dụng để lọc kết quả của các tài nguyên được đại diện bởi url, nhưng tôi đã thấy phương pháp này cũng được sử dụng

GET /users?id={id}
GET /users?email={email}

Câu hỏi của tôi là, trong số tất cả các phương pháp này, phương pháp nào sẽ có ý nghĩa nhất đối với các nhà phát triển sử dụng apis và tại sao? Tôi tin rằng không có quy tắc nào được đặt ra khi nói đến thiết kế url REST và quy ước đặt tên, nhưng tôi chỉ muốn biết mình nên thực hiện theo lộ trình nào để giúp các nhà phát triển hiểu rõ hơn về apis.

Tất cả sự trợ giúp được đánh giá cao!


1
Tôi biết điều này hơi cũ nhưng khi tìm kiếm các nguồn tương tự, tôi vấp phải câu hỏi này và câu hỏi bạn đang tìm kiếm. Tôi tin rằng nó là này một stackoverflow.com/a/9743414/468327
Joel Berger

Câu trả lời:


102

Theo kinh nghiệm của tôi, GET /users/{id} GET /users/email/{email}là cách tiếp cận phổ biến nhất. Tôi cũng mong đợi các phương thức trả về 404 Not Found nếu người dùng không tồn tại với idhoặc được cung cấp email. Tôi cũng sẽ không ngạc nhiên khi thấy GET /users/id/{id}(mặc dù theo ý kiến ​​của tôi, nó là thừa).

Nhận xét về các cách tiếp cận khác

  1. GET /users/id={id} GET /users/email={email}
    • Tôi không nghĩ rằng tôi đã thấy điều này, và nếu tôi đã nhìn thấy nó, nó sẽ rất khó hiểu. Nó gần giống như nó đang cố gắng bắt chước các tham số truy vấn với các tham số đường dẫn.
  2. GET /users?id={id} GET /users?email={email}
    • Tôi nghĩ rằng bạn đã đánh vào đầu khi bạn đề cập đến việc sử dụng các tham số truy vấn để lọc.
    • Có bao giờ nên gọi tài nguyên này bằng cả dấu idemail(ví dụ GET /users?id={id}&email={email}) không? Nếu không, tôi sẽ không sử dụng một phương pháp tài nguyên đơn lẻ như thế này.
    • Tôi mong chờ phương pháp này để lấy một danh sách của người sử dụng với các thông số truy vấn tùy chọn để lọc, nhưng tôi sẽ không mong đợi id, emailhoặc bất kỳ định danh duy nhất là một trong các thông số. Ví dụ: GET /users?status=BANNEDcó thể trả về danh sách người dùng bị cấm.

Kiểm tra câu trả lời này từ một câu hỏi liên quan.


Cảm ơn bạn đã nhập. Thực ra bạn đã đúng. Có vẻ như tôi đã đọc # 1 trong cuốn sách "RESTful java with Jax-rs" nhưng hơi lạc đề. Nhưng tôi nhớ rất rõ rằng mình đã đọc nó như một câu trả lời cho một trong những câu hỏi trên chính stackoverflow (tin tôi đi khi tôi nói rằng tôi đang rất cố gắng tìm ra liên kết đó để chứng minh cho đồng nghiệp của mình :)) và số 2 chính xác là tôi đã tìm kiếm. Một số phản hồi về thiết kế. Cảm ơn bạn!
shahshi

Tái bút: Tôi không chắc liệu đăng điều này có trái với quy tắc ở đây hay không nhưng bạn có thể cũng có thể làm sáng tỏ một trong những câu hỏi khác của tôi? xin vui lòng? :) stackoverflow.com/questions/20508008/…
shahshi15

chỉ để làm rõ về tuyên bố dự phòng của bạn cho /users/id/{id}, điều này cho phép mở rộng chức năng, chỉ cho phép truy cập một tài nguyên thông qua một số định danh (id, hướng dẫn, tên). cũng được trả lời ở đây
Daniel Dubovski,

4
Câu trả lời của tôi là cách thích hợp để tham chiếu đến một Người dùng cụ thể, ví dụ: sẽ là / users / {id}. Nếu bạn muốn tìm người dùng bằng một địa chỉ email cụ thể không phải là số nhận dạng duy nhất cho những người dùng mà tôi sẽ làm / người dùng? Email = {email} vì đó là một cách để lọc tập hợp người dùng, không xác định một tài nguyên cụ thể bằng tài nguyên đó định danh là / users / {id} là.
Kevin M

Câu trả lời chính xác! Thích cho nó. Điều duy nhất tôi muốn giới thiệu để làm cũng là để thay đổi API của bạn một chút là REST nên tên trung tâm để các nguồn lực của bạn ánh xạ nên một cái gì đó như: GET /user/1234khôngGET /users/123
Sammy

36

Nhìn vào điều này một cách thực dụng, bạn có một tập hợp người dùng:

/users   # this returns many

Mỗi người dùng có một vị trí tài nguyên dành riêng:

/users/{id}    # this returns one

Bạn cũng có một số cách để tìm kiếm người dùng:

/users?email={email}
/users?name=*bob*

Vì đây là tất cả các tham số truy vấn cho / người dùng, tất cả chúng sẽ trả về danh sách .. ngay cả khi đó là danh sách 1.

Tôi đã viết một bài đăng trên blog về thiết kế API RESTful thực dụng ở đây nói về điều này, trong số những thứ khác, tại đây: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api


Cảm ơn vì đã trả lời vinay. Nhưng nếu chúng ta nghĩ về điều này ở một góc độ khác, thì {email} cũng giống như {id} LUÔN LUÔN trả về một kết quả. Nếu chúng ta thực sự đang tìm kiếm, tại sao không sử dụng? Id = {id} cũng như cho email? Tôi đã tự hỏi liệu có cách nào để nhất quán không. PS: mới sử dụng stackoverflow, không biết tôi chỉ có thể lên một câu trả lời. Nhưng cảm ơn bạn đã trả lời! Cảm kích điều đó. Có lẽ bạn cũng có thể giúp tôi với vấn đề này: stackoverflow.com/questions/20508008/…
shahshi15

7
Đây là lúc khía cạnh "thiết kế" của thiết kế API phát huy tác dụng. Tài nguyên của bạn nên có một vị trí chuyên dụng. Vị trí ở đâu? Vị trí theo id? Nếu vậy, bạn không "tìm kiếm" bằng id, bạn "lấy" bằng id. Nhưng bạn tìm kiếm bằng mọi thứ khác. Tất nhiên, không có quy tắc cố định nào ở đây. Đó chỉ là một góc nhìn :)
Vinay Sahni

6
Tôi cũng sẽ tranh luận rằng cách này API của bạn ổn định hơn. Bạn thực sự biết rằng id của bạn là duy nhất nhưng bạn có thực sự chắc chắn về địa chỉ email không? Ngay cả khi nó là duy nhất, nó có thể không phải là vĩnh viễn vì người dùng có thể thay đổi nó. Vì vậy, / users? Email = {email} nói rõ rằng đây thực sự là một truy vấn chứ không phải quyền truy cập vào tài nguyên có số nhận dạng permament.
lex82,

Tôi tin rằng đây thực sự là câu trả lời chính xác hơn. Lọc bộ sưu tập theo địa chỉ email có thể dựa trên ký tự đại diện, vì vậy nó không phải lúc nào cũng trả về một kết quả.
Kevin M

@VinaySahni Bạn sẽ nói gì về một mẫu như: /user?by=email&email="abc@pqr.com "/ user? By = id & id =" xashkhx "/ users? FilterA =" a "& filterB =" b "(số nhiều cho nhiều người dùng)
Shasak

2

Giới thiệu về tài nguyên người dùng

trên đường dẫn, /usersbạn sẽ luôn nhận được một tập hợp các tài nguyên người dùng được trả về.

trên con đường /users/[user_id]bạn có thể mong đợi một số điều sẽ xảy ra:

  1. bạn sẽ nhận được một tài nguyên singleton đại diện cho tài nguyên người dùng với số nhận dạng của nó [user_id] hoặc
  2. không tìm thấy phản hồi 404 nếu không có người dùng nào có id [user_id] tồn tại hoặc
  3. 401 bị cấm nếu bạn không được phép truy cập tài nguyên người dùng được yêu cầu.

Mỗi singleton được xác định duy nhất bởi đường dẫn và mã định danh của nó và bạn sử dụng chúng để tìm tài nguyên. Không thể sử dụng một số đường dẫn cho singleton.

Bạn có thể truy vấn đường dẫn /usersbằng các tham số truy vấn ( GETParameters). Thao tác này sẽ trả về một bộ sưu tập với những người dùng đáp ứng các tiêu chí được yêu cầu. Bộ sưu tập được trả về phải chứa tài nguyên người dùng, tất cả đều có đường dẫn tài nguyên nhận dạng của họ trong phản hồi.

Tham số có thể là bất kỳ trường nào có trong tài nguyên của bộ sưu tập; firstName, lastName,id

Về email

Email có thể là tài nguyên hoặc thuộc tính / trường của tài nguyên người dùng.

- Email là tài sản của người dùng:

Nếu trường là thuộc tính của người dùng thì phản hồi của người dùng sẽ trông giống như sau:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: 'john.doe@example.com'
  ...
}

Điều này có nghĩa không có thiết bị đầu cuối đặc biệt cho email, nhưng bây giờ bạn có thể tìm thấy một người dùng qua email của mình bằng cách gửi yêu cầu sau đây: /users?email=john.doe@example.com. Cái nào (giả sử email là duy nhất cho người dùng) sẽ trả về một bộ sưu tập có một mục người dùng khớp với email.

- Email như một tài nguyên:

Nhưng nếu email từ người dùng cũng là tài nguyên. Sau đó, bạn có thể tạo một API để /users/[user_id]/emailstrả về một tập hợp các địa chỉ email cho người dùng có id user_id. /users/[user_id]/emails/[email_id]trả về email của người dùng với user_id và ['email_id']. Những gì bạn sử dụng làm số nhận dạng là tùy thuộc vào bạn, nhưng tôi sẽ gắn bó với một số nguyên. Bạn có thể xóa email khỏi người dùng bằng cách gửi DELETEyêu cầu đến đường dẫn xác định email bạn muốn xóa. Vì vậy, ví dụ DELETEtrên /users/[user_id]/emails/[email_id]sẽ xóa email có email_id được sở hữu bởi người dùng với user_id. Nhiều khả năng chỉ người dùng đó mới được phép thực hiện thao tác xóa này. Những người dùng khác sẽ nhận được phản hồi 401.

Nếu người dùng chỉ có thể có một địa chỉ email, bạn có thể gắn vào /users/[user_id]/email Điều này trả về một tài nguyên đơn lẻ. Người dùng có thể cập nhật địa chỉ email của mình bằng cách PUTnhập địa chỉ email tại url đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.