Spring Rest : Handling POST requests, at server end

2.4k views Asked by At

I am asking this question based on the answers in this link

POST request via RestTemplate in JSON

I actually wanted to send JSON from client and receive the same at REST server. Since the client part is done in the link I mentioned above. For the same how would I handle that request at server end.

CLIENT:

// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);

// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);

// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
  .exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
  JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
  // nono... bad credentials
}

SERVER:

@RequestMapping(method=RequestMethod.POST, value = "/login")
    public ResponseEntity<String> login(@RequestBody HttpEntity<String> entity) {
        JSONObject jsonObject = new JSONObject(entity.getBody());
        String username = jsonObject.getString("username");
        return new ResponseEntity<>(username, HttpStatus.OK);
    }

This gives me 400 bad request error at client side. Hoping for some clues about how to handle this at server side.

2

There are 2 answers

1
sag On BEST ANSWER

HTTPEntity should not be used in your server method. Instead use the argument which is being passed to HTTPEntity from your client. In your case it has to String since you are passing string from client. Below code should work for you.

@RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(@RequestBody String jsonStr) {
    System.out.println("jsonStr  " + jsonStr);
    JSONObject jsonObject = new JSONObject(jsonStr);
    String username = jsonObject.getString("username");
    return new ResponseEntity<String>(username, HttpStatus.OK);
}  

My advice is to create bean class and use it in server and client instead of converting it to String. It will improve readability of the code.

1
manish On

When using the Spring RestTemplate, I usually prefer to exchange objects directly. For example:

Step 1: Declare and define a data holder class

class User {
  private String username;
  private String password;

  ... accessor methods, constructors, etc. ...
}

Step 2: Send objects of this class to the server using RestTemplate

... You have a RestTemplate instance to send data to the server ...

// You have an object to send to the server, such as:
User user = new User("user", "secret");

// Set HTTP headers for an error-free exchange with the server.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

// Generate an HTTP request payload.
HttpEntity<User> request = new HttpEntity<User>(user, headers);

// Send the payload to the server.
restTemplate.exchange("[url]", [HttpMethod], request, User.class);

Step 3: Configure a ContentNegotiatingViewResolver on the server

Declare a bean of the type ContentNegotiatingViewResolver in the Spring XML or Java configuration. This will help the server automatically bind HTTP requests with bean objects.

Step 4: Receive the request on the server

@RestController
@RequestMapping("/user")
class UserAPI {
  @RequestMapping(method = RequestMethod.POST)
  @ResponseBody
  public User create(User user) {
    // Process the user.

    // Possibly return the same user, although anything can be returned.
    return user;
  }
}

The ContentNegotiatingViewResolver ensures that the incoming request gets translated into a User instance without any other intervention.

Step 5: Receive the response on the client

// Receive the response.
HttpEntity<User> response = restTemplate.exchange("[url]", [HttpMethod], request, User.class);

// Unwrap the object from the response.
user = response.getBody();

You will notice that the client and the server both use the same bean class (User). This keeps both in sync as any breaking change in the bean structure would immediately cause a compilation failure for one or both, necessitating a fix before the code is deployed.