Thiết kế API truy vấn RESTful với một danh sách dài các tham số truy vấn [đã đóng]


153

Tôi cần thiết kế API truy vấn RESTful, trả về một tập hợp các đối tượng dựa trên một vài bộ lọc. Phương thức HTTP thông thường cho việc này là GET. Vấn đề duy nhất là, nó có thể có ít nhất một tá bộ lọc và nếu chúng ta vượt qua tất cả chúng làm tham số truy vấn, URL có thể khá dài (đủ lâu để bị chặn bởi một số tường lửa).

Giảm số lượng tham số không phải là một lựa chọn.

Một cách khác tôi có thể nghĩ đến là sử dụng phương thức POST trên URI và gửi các bộ lọc như một phần của phần POST. Đây có phải là chống lại RESTfull (Thực hiện cuộc gọi POST để truy vấn dữ liệu).

Bất cứ ai có bất kỳ đề nghị thiết kế tốt hơn?


2
Sử dụng tên tham số ngắn (1-char, v.v.)?
Madbreaks

2
Nó có thể không thực sự RESTful, nhưng tôi nghĩ bạn phải thực tế khi nói đến GET và POST. Nếu bạn có nhiều biến để gửi và bạn không thể giảm chúng, tôi sẽ ĐĂNG chúng. Tôi không thích quá nhiều URL, nhưng đó chỉ là tôi.
Doug Dawson

Cảm ơn. Mặc dù câu hỏi này đã được đóng lại, nhưng nó chính xác là câu hỏi mà tôi cần một câu trả lời. Tôi vui mừng bạn đã hỏi.
Casey Crookston

Câu trả lời:


141

Hãy nhớ rằng với API REST, tất cả chỉ là câu hỏi về quan điểm của bạn.

Hai khái niệm chính trong API REST là điểm cuối và tài nguyên (thực thể). Đặt một cách lỏng lẻo, một điểm cuối hoặc trả về tài nguyên thông qua GET hoặc chấp nhận tài nguyên thông qua POST và PUT, v.v. (hoặc kết hợp các yếu tố trên).

Chúng tôi chấp nhận rằng với POST, dữ liệu bạn gửi có thể hoặc không dẫn đến việc tạo ra một tài nguyên mới và (các) điểm cuối liên quan của nó, rất có thể sẽ không "sống" dưới url POSTed. Nói cách khác, khi bạn POST bạn gửi dữ liệu ở đâu đó để xử lý. Điểm cuối POST không phải là nơi thường tìm thấy tài nguyên.

Trích dẫn từ RFC 2616 (với các phần không liên quan được bỏ qua và các phần có liên quan được tô sáng):

9,5 BÀI ĐĂNG

Phương thức POST được sử dụng để yêu cầu máy chủ gốc chấp nhận thực thể được đính kèm trong yêu cầu dưới dạng cấp dưới mới của tài nguyên được xác định bởi URI yêu cầu trong Dòng yêu cầu. POST được thiết kế để cho phép một phương thức thống nhất bao gồm các chức năng sau:

  • ...
  • Cung cấp một khối dữ liệu, chẳng hạn như kết quả của việc gửi biểu mẫu, cho quy trình xử lý dữ liệu;
  • ...

...

Hành động được thực hiện bởi phương thức POST có thể không dẫn đến một tài nguyên có thể được xác định bởi một URI . Trong trường hợp này, 200 (OK) hoặc 204 (Không có nội dung) là trạng thái phản hồi phù hợp, tùy thuộc vào việc phản hồi có bao gồm thực thể mô tả kết quả hay không .

Nếu tài nguyên đã được tạo trên máy chủ gốc, phản hồi NÊN là 201 (Đã tạo) ...

Chúng tôi đã quen với các điểm cuối và tài nguyên đại diện cho 'mọi thứ' hoặc 'dữ liệu', có thể là người dùng, tin nhắn, sách - bất cứ điều gì mà miền vấn đề ra lệnh. Tuy nhiên, điểm cuối cũng có thể hiển thị một tài nguyên khác - ví dụ: kết quả tìm kiếm.

Hãy xem xét ví dụ sau:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

Đây là một CRUD REST điển hình. Tuy nhiên, nếu chúng ta thêm vào:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

Không có gì không RESTful về điểm cuối này. Nó chấp nhận dữ liệu (thực thể) dưới dạng cơ thể yêu cầu. Dữ liệu đó là Tiêu chí tìm kiếm - một DTO như mọi thứ khác. Điểm cuối này tạo ra một tài nguyên (thực thể) để đáp ứng yêu cầu: Kết quả tìm kiếm . Tài nguyên kết quả tìm kiếm là tạm thời, được phục vụ ngay lập tức cho khách hàng, không chuyển hướng và không bị lộ ra khỏi một số url chính tắc khác.

Đó vẫn là REST, ngoại trừ các thực thể không có sách - thực thể yêu cầu là tiêu chí tìm kiếm sách và thực thể phản hồi là kết quả tìm kiếm sách.


Bạn có thể đề xuất một số quy ước đặt tên cho DTO không?
Kwadz

Cá nhân tôi sẽ đi với BooksSearchCriteriaDTOBooksSearchResultsDTO.
Amir Abiri

mã phản hồi HTTP tốt nhất cho trường hợp POST / sách / tìm kiếm này là gì? 201 vẫn áp dụng?
L. Holanda

8
201 thì ngược lại - nó ngụ ý rằng một tài nguyên đã được tạo ra. Một tài nguyên dự kiến ​​sẽ có URI duy nhất ở đâu đó. 201 là phù hợp khi POSTđược sử dụng cho phần C của CRUD. Tôi sẽ đi với 200 cũ, tùy chọn có thể với 204 cho kết quả tìm kiếm trống.
Amir Abiri

@AmirAbiri cảm ơn bạn rất nhiều.
mohamed-mhiri

84

Rất nhiều người đã chấp nhận thực tế rằng một GET với chuỗi truy vấn quá dài hoặc quá phức tạp (ví dụ: chuỗi truy vấn không dễ dàng xử lý dữ liệu lồng nhau) có thể được gửi dưới dạng POST thay vào đó, với dữ liệu phức tạp / dài được biểu thị trong phần thân của yêu cầu.

Tra cứu thông số kỹ thuật cho POST trong thông số HTTP. Nó rất rộng. (Nếu bạn muốn lái tàu chiến qua kẽ hở trong REST ... hãy sử dụng POST.)

Bạn mất một số lợi ích của ngữ nghĩa GET ... như tự động thử lại vì GET là không cần thiết, nhưng nếu bạn có thể sống với điều đó, có thể dễ dàng hơn để chấp nhận xử lý các truy vấn thực sự dài hoặc phức tạp với POST.

(lol phân tích dài ... Gần đây tôi đã phát hiện ra rằng bằng thông số HTTP, GET có thể chứa phần thân tài liệu. Có một phần nói rằng, "Bất kỳ yêu cầu nào cũng có thể có phần thân tài liệu ngoại trừ phần được liệt kê trong phần này" ... và phần mà nó đề cập không liệt kê bất kỳ. Tôi đã tìm kiếm và tìm thấy một chủ đề trong đó các tác giả HTTP đang nói về điều đó, và đó là cố ý, do đó các bộ định tuyến và như vậy sẽ không phải phân biệt giữa các thông điệp khác nhau. Tuy nhiên, trong thực hành rất nhiều phần cơ sở hạ tầng làm rơi phần thân của một GET. Vì vậy, bạn có thể NHẬN với các bộ lọc được thể hiện trong cơ thể, như POST, nhưng bạn sẽ gieo xúc xắc.)


11
Xem thêm câu hỏi này để biết thêm thảo luận về HTTP GET với cơ thể.
RickyA

6

Tóm lại: Tạo POST nhưng ghi đè phương thức HTTP bằng tiêu đề Ghi đè phương thức X-HTTP .

Yêu cầu thực sự

BÀI ĐĂNG / sách

Cơ thể thực thể

{"tiêu đề": "Ipsum", "năm": 2017}

Tiêu đề

Ghi đè phương thức X-HTTP: NHẬN

Về phía máy chủ, hãy kiểm tra xem tiêu đề X-HTTP-Phương thức ghi đè có tồn tại hay không, sau đó lấy giá trị của nó làm phương thức để xây dựng tuyến đến điểm cuối cuối cùng trong phần phụ trợ. Ngoài ra, lấy phần thân thực thể làm chuỗi truy vấn. Từ quan điểm phụ trợ, yêu cầu chỉ trở thành một NHẬN đơn giản.

Bằng cách này bạn giữ cho thiết kế hài hòa với các nguyên tắc REST.

Chỉnh sửa: Tôi biết giải pháp này ban đầu được dự định để giải quyết vấn đề động từ PATCH trong một số trình duyệt và máy chủ nhưng nó cũng hoạt động với tôi với động từ GET trong trường hợp URL rất dài là vấn đề được mô tả trong câu hỏi.


2
IETF không dùng các tiêu đề HTTP có tiền tố X: tools.ietf.org/html/rfc6648
jannis


@jannis RFC bạn liên kết ở lại 1.4. nó không đưa ra khuyến nghị nào về X-việc loại bỏ hiện tại và 1.5. nó không ghi đè các thông số kỹ thuật hiện có. ... X-IMO sẽ vẫn ở đây.
Jan Molnar

-3

Nếu bạn đang phát triển bằng Java và JAX-RS, tôi khuyên bạn nên sử dụng @QueryParam với @GET

Tôi đã có cùng một câu hỏi khi tôi cần phải đi qua một danh sách.

Xem ví dụ:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

Mẫu URI: Quảng cáo poc / test? Code = 1 & code = 2 & code = 3

@QueryParam sẽ tự động chuyển đổi tham số truy vấn, order orderBy = age & orderBy = name tên thành java.util.List.


Sẽ tốt hơn nếu bạn giải thích ví dụ của bạn. Nó được viết bằng ngôn ngữ lập trình nào?
Aleks Andreev

Xin chào @AleksAndreev. Cảm ơn quan điểm của bạn. Nó đã tốt hơn? tks
acacio.martins

Câu hỏi này là về thiết kế của dịch vụ RESTful, không phải về việc triển khai. Câu trả lời này không trả lời câu hỏi.
Khỉ dị giáo

@ user1331413 IMHO có, bây giờ tốt hơn. Cảm ơn bạn vì nỗ lực của bạn .. Tuy nhiên, như Mike McCaughan đã nói, câu hỏi là về khái niệm REST, thay vì thực hiện
Aleks Andreev
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.