With a simple Spring Boot application, I am trying to understand the difference between the Spring Boot annotations @RequestParam and @RequestBody and their respective use. The Spring documentation defines @RequestParam as an 'Annotation which indicates that a method parameter should be bound to a web request parameter' and @RequestBody as an ‘Annotation which indicates that a method parameter should be bound to the web request body.’ It is thus fair to assume that both annotations and associated methods can be used as equifinal alternatives (different methods for similar results) to pass parameters to a backend application, for example to insert the values ‘email', 'username’ and ‘password’ in a User database (just forgetting for the simplicity about the necessary encryption of the password).
Therefore, one could expect that the code snipped below
@PostMapping
public User save(@RequestBody User user) {
return userService.createUser(user);
}
be equivalent to
@PostMapping(value = "/users")
public ResponseEntity<User> createUser(
@RequestParam String email,
@RequestParam String username,
@RequestParam String password
) {
try {
User user = new User();
user.setEmail(email);
user.setUsername(username);
user.setPassword(password);
userService.createUser(user);
return ResponseEntity.noContent().build();
} catch (Exception exception) {
return new ResponseEntity<>(HttpStatus.I_AM_A_TEAPOT);
}
}
Trying the @RequestBody alternative with Postman results in a 200 OK response:
But trying the @RequestParam alternative results in a 400 ‘bad request’ error:
Why does this @RequestParam approach triggers an error while the apparently equivalent approach @RequestBody works as expected?
For the completeness, the user model is given below:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String username;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
The repository is given below:
public interface UserRepository extends JpaRepository<User, Long> {}
The user service interface is given below:
public interface UserService {
List<User> getAllUsers();
User getUserById(Long id);
User createUser(User user);
void deleteUser(Long id);
}
and the user service is given below:
@Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
@Override
public User createUser(User user) {
return userRepository.save(user);
}
@Override
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
@Override
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}