Mục lục
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu 2 HTTP method thường xuyên được sử dụng trong REST là POST và PUT. Mặc dù sử dụng rất thường xuyên nhưng đôi khi các developer lại phân vân không biết nên chọn một trong hai method này để triển khai một endpoint API.
Trong bài viết này chúng ta sẽ cùng nhau tìm ra sự khác biệt và cách sử dụng đúng 2 method này thông qua ví dụ sử dụng Spring Boot.
Sự khác nhau giữa POST và PUT
Trong một ứng dụng REST, các clients sẽ gửi các request thông qua các HTTP method đến server để thêm, xoá, chỉnh sửa hoặc truy cập các tài nguyên. Mặc dù PUT và POST đều có thể sử dụng để khởi tạo tài nguyên, nhưng chúng lại có sự khác rất lớn trong mục đích sử dụng.
Theo tiêu chuẩn RFC 2616, POST method được dùng để gửi các request kèm theo một entity đến server yêu cầu tạo một tài nguyên mới dựa trên entity được cung cấp.
Mặt khác, PUT method nên kèm theo một định danh (thường là ID) cùng với một entity. Nếu một tài nguyên được tìm thấy bởi mã định danh kèm theo thì tài nguyên này sẽ được thay thế bởi các giá trị trong entity kèm theo. Ngược lại, PUT method sẽ tạo một tài nguyên dựa trên entity đã cung cấp.
Một điểm khác biệt quan trọng giữa POST và PUT đó là nếu chúng ta gọi PUT method nhiều lần thì sẽ nó tạo hoặc cập nhật cùng một tài nguyên (dựa vào mã định danh). Còn với POST thì việc chúng ta thực thi nhiều lần với cùng một enity thì nó sẽ tạo ra nhiều tài nguyên ở phía server có giá trị tương tự nhau.
Triển khai ví dụ
Để làm rõ hơn sự khác biệt giữa POST và PUT, chúng ta sẽ cùng nhau tạo một ứng dụng RESTful đơn giản sử dụng Spring Boot. Mục đích chính của ứng dụng này là dùng để lưu trữ tên và địa chỉ của người dùng.
Maven Dependencies
Để tạo REST api chúng ta cần đến gói spring-boot-starter-web, Spring Data JPA và database được sử dụng đó là H2. Ngoài ra mình còn sử dụng lombok để generate các hàm setter, getter, constructor.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
Domain entity và Repository
Tiến hành tạo một Address entity và repository cho nó dùng để thao tác với database H2.
package com.deft; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity @Getter @Setter @NoArgsConstructor public class Address { private @Id @GeneratedValue Long id; private String name; private String city; private String postalCode; }
Bước tiếp theo chúng ta sẽ tạo AddressRepository sử dụng Spring data JPA cung cấp sẵn cho chúng ta các hàm insert, update, delete, find v.v
package com.deft; import org.springframework.data.jpa.repository.JpaRepository; public interface AddressRepository extends JpaRepository<Address, Long> { }
REST Controller
Bước cuối cùng chúng ta sẽ tạo các API endpoint cho ứng dụng, với POST method để tạo một address mới và lưu xuống database. PUT method dùng để cập nhật một address đã tồn tại trước đó dựa theo ID kèm theo, nếu không tìm thấy nó sẽ tạo một address mới.
package com.deft; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController public class AddressController { @Autowired private AddressRepository repository; @PostMapping("/addresses") public Address createNewAddress(@RequestBody Address newAddress) { return repository.save(newAddress); } @PutMapping("/addresses/{id}") public Address update(@RequestBody Address newAddress, @PathVariable Long id) { return repository.findById(id) .map(address -> { address.setCity(newAddress.getCity()); address.setPostalCode(newAddress.getPostalCode()); return repository.save(address); }) .orElseGet(() -> repository.save(newAddress)); } }
CURL Request
Sau khi hoàn thành các bước trên, giờ đây chúng ta có thể khởi chạy ứng dụng và kiểm thử với curl request.
Để khởi tạo một address mới, chsung ta sẽ gửi một POST request kèm them chuỗi JSON chứa thông tin của Address entity.
curl -X POST --header 'Content-Type: application/json' \ -d '{ "name": "John Doe", "city": "Berlin", "postalCode": "10585" }' \ http://localhost:8080/addresses
Sau khi address được tạo ra, chúng ta có thể cập nhật nó bằng cách sử dụng PUT method, giả sử address vừa được tạo lúc nảy có ID=1.
curl -X PUT --header 'Content-Type: application/json' \ -d '{ "name": "John Doe", "city": "Frankfurt", "postalCode": "60306" }' \ http://localhost:8080/addresses/1
Tóm lược
Như vậy qua bài viết này chúng ta đã tìm hiểu được sự khác nhau giữa POST và PUT method. Hy vọng trong những lần tới các bạn có thể sử dụng chúng một cách đúng đắn hơn.
Các bạn có thể download source code demo tại đây: post-put-in-different.