Tôi sắp bắt đầu phát triển trên một api còn lại mới trong Java. Câu hỏi của tôi là về việc sử dụng PATCH - Tại sao?Trong một API REST java, sử dụng PATCH vs PUT để cập nhật một thực thể
phép nói rằng, chúng tôi có một thực thể có tên Address.java
public class Address {
@Id
private Long id
@NotNull
private String line1;
private String line2; //optional
@NotNull
private String city;
@NotNull
private String state;
}
Để tạo một địa chỉ mới, tôi sẽ làm theo yêu cầu này http:
POST http://localhost:8080/addresses
với yêu cầu sau:
{
"line1" : "mandatory Address line 1",
"line2" : "optional Address line 2",
"city" : "mandatory City",
"state" : "cd"
}
Giả sử bản ghi được tạo có id 1
Các tương ứng @RestController AddressResource.java sẽ có phương pháp này:
@PostMapping(value = "/addresses")
public ResponseEntity<Address> create(@valid Address newAddress) {
addressRepo.save(newAddress);
}
@valid sẽ đảm bảo các thực thể có giá trị trước khi lưu trữ dữ liệu vào bảng.
Bây giờ giả sử, tôi chuyển từ căn hộ của tôi ở trên xuống một căn nhà trên phố. Nếu tôi sử dụng một bản vá, nó trở nên
PATCH http://localhost:8080/addresses/1
với yêu cầu tải trọng:
{
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : null
}
Phương pháp @RestController tương ứng sẽ là:
@PatchMapping(value = "/addresses/{id}")
public ResponseEntity<Address> patchAddress(@PathVariable Long id, Address partialAddress)
{
Address dbAddress = addressRepo.findOne(id);
if (partialAddress.getLine1() != null) {
dbAddress.setLine1(partialAddress.getLine1());
}
if (partialAddress.getLine2() != null) {
dbAddress.setLine2(partialAddress.getLine2());
}
if (partialAddress.getCity() != null) {
dbAddress.setCity(partialAddress.getCity());
}
if (partialAddress.getState() != null) {
dbAddress.setState(partialAddress.getState());
}
addressRepo.save(dbAddress)
}
Bây giờ nếu bạn truy vấn bảng, thắng' địa chỉ của tôi là gì?
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : "optional Address line 2", <-- INCORRECT. Should be null.
"city" : "mandatory City",
"state" : "cd"
Như có thể thấy, các cập nhật ở trên dẫn đến giá trị không chính xác cho dòng 2. Điều này là bởi vì trong java tất cả các biến mẫu trong lớp Địa chỉ được khởi tạo thành null (hoặc giá trị mặc định ban đầu nếu chúng là nguyên thủy) khi một lớp được khởi tạo. Vì vậy, không có cách nào để phân biệt giữa line2 được thay đổi thành null từ giá trị mặc định.
Câu hỏi 1) Có cách nào tiêu chuẩn để giải quyết vấn đề này không?
Một nhược điểm nữa là, tôi không thể sử dụng chú thích @Valid để xác nhận yêu cầu tại điểm nhập cảnh - coz nó chỉ là một phần. Vì vậy, dữ liệu không hợp lệ có thể xâm nhập vào hệ thống.
Ví dụ, hãy tưởng tượng là có trường bổ sung với định nghĩa sau đây:
@Min(0)
@Max(100)
private Integer lengthOfResidencyInYears,
Và người dùng vô tình gõ 190 (khi họ thực sự có nghĩa là 19 năm), nó sẽ không thất bại.
Thay vì PATCH, nếu tôi đã sử dụng PUT, khách hàng sẽ cần phải gửi đối tượng địa chỉ đầy đủ. này có lợi thế mà tôi có thể sử dụng @Valid để đảm bảo rằng địa chỉ thực sự có giá trị
Nếu một làm tiền đề rằng một GET luôn phải được thực hiện trước khi thực hiện bất kỳ bản cập nhật, tại sao không phải là một sử dụng PUT hơn PATCH? Tôi có thiếu gì đó không?
Ngoài
Kết luận của tôi là các nhà phát triển sử dụng ngôn ngữ kiểu động là những người ủng hộ của việc sử dụng PATCH như tôi không thể nhìn thấy bất kỳ lợi ích để sử dụng nó từ một dòng ngôn ngữ tĩnh đánh máy Java hoặc C#. Nó chỉ có vẻ thêm phức tạp hơn.
dường như trạng thái hợp lệ, sau khi PATCH yêu cầu truy vấn db của bạn sẽ hiển thị dòng: "tùy chọn Dòng địa chỉ 2", vì bạn đang kiểm tra, partialAddress.getLine2()! = Null. – kuhajeyan
Một yêu cầu vá phải chứa các chỉ lệnh được máy khách tính toán mà máy chủ có thể sử dụng để chuyển đổi trạng thái A của một số tài nguyên thành trạng thái B và không chỉ là một phần cập nhật đơn giản. Đọc thêm: [SO tài liệu] (http://stackoverflow.com/documentation/http/3423/http-for-apis/11812/edit-a-resource#t=201610031245323472567) và [bài đăng blog tốt] (http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/) –
Đây là một câu hỏi hay. Liên quan đến null trong dòng 2 là chính xác bởi vì bạn tự ánh xạ các trường của bạn và bạn kiểm tra các giá trị không null để ghi đè lên. Hiện tại, tôi đang làm việc trên một dự án mà chúng tôi sử dụng [Dozer] (http://dozer.sourceforge.net/documentation/usage.html) và bạn có thể chọn ánh xạ các giá trị rỗng. Dù sao, chúng tôi sử dụng POST để thêm/tạo tài nguyên và PUT để sửa đổi chúng, tuy nhiên với trình ánh xạ này, nó có thể thực hiện ánh xạ một phần. Vì vậy, im tranh luận nếu đây là cách ưa thích hoặc tôi nên sử dụng POST (tạo), PUT (cập nhật đầy đủ), PATCH (cập nhật một phần). –