Post JSON to spring REST webservice

After making a GET request to a REST service the natural progression is to POST information back to the server. In this episode we will look at how to post json to spring controller and have it automatically convert JSON to arraylist, object or multiple objects.

Detailed Video Notes

Understanding @RequestBody

The first thing to understand is how json binds to a java object. The @RequestBody method parameter annotation should bind the json value in the HTTP request body to the java object by using a HttpMessageConverter. In episode 13 how to return XML in REST, we discussed the responsibility of HttpMessageConverter. To recap HttpMessageConverter is responsible for converting the HTTP request message to an assoicated java object. In our case want to convert JSON to a java object when a request is made. Spring will look specifically for a HttpMessageConverter assoicated to the mime type to perform the conversion. Since spring boot configures it automatically if jackson is on our class path MappingJackson2MessageConverter is used. Alternatively you can configure GsonHttpMessageConverter based on google gson library which was offically release in spring version 4.1.

In code we annotate the method parameter with spring @RequestBody which looks like:

@RequestMapping(value = "/", method = RequestMethod.POST)
public ResponseEntity<Car> update(@RequestBody Car car) {
    ...
}

Project set up

[1:15]

Creating a project

We will create a new project with spring boot and create a POJO object Car which will post to a spring controller. One thing to note in our snippets is we won't discuss REST api design topic or make the actual update to a persistence layer.

public class Car {

    private String VIN;
    private String color;
    private Integer miles;

    //...
}

Get request

[1:56]

Before we post JSON, lets create a method to return a Car and make a request to http://localhost:8080/. You will notice that we are using ResponseEntity as the method return type. ResponseEntity is a class that allows you to modify request and response headers. An important design aspect of REST services is also to return the proper HTTP status code and in this case a 200.

@RequestMapping(value = "/")
public ResponseEntity<Car> get() {

    Car car = new Car();
    car.setColor("Blue");
    car.setMiles(100);
    car.setVIN("1234");

    return new ResponseEntity<Car>(car, HttpStatus.OK);
}

Which should return a json response:

{
    color: "Blue"
    miles: 100
    vin: "1234"
}

Json to java object

[2:2]

You might want to update the Car object by posting json to a URL. A more detailed user story would be, as a user I want to be able update attributes of my car. We will create @RequestMapping and specify method = RequestMethod.POST which will tell spring to use this method when a post occurs. When the post is made lets increment the miles by 100.

@RequestMapping(value = "/", method = RequestMethod.POST)
public ResponseEntity<Car> update(@RequestBody Car car) {

    if (car != null) {
        car.setMiles(car.getMiles() + 100);
    }

    // TODO: call persistence layer to update
    return new ResponseEntity<Car>(car, HttpStatus.OK);
}

Using the sample JSON above, lets make a request using advanced rest client chrome plugin and result should increment the miles field by 100.

{
    "color":"Blue",
    "miles":200,
    "vin":"1234"
}

Json to arraylist

[2:48]

Next, you might have a life event where you inherit a car, get married or your child starts to drive (good luck!). Now we have a series of cars we want to update the mileage. Lets create a new request mapping to http://localhost:8080/cars which accepts a json array as a parameter. Again, we will increment mileage by 100 using a java 8 foreach loop.

@RequestMapping(value = "/cars", method = RequestMethod.POST)
public ResponseEntity<List<Car>> update(@RequestBody List<Car> cars) {

    cars.stream().forEach(c -> c.setMiles(c.getMiles() + 100));
    
    // TODO: call persistence layer to update
    return new ResponseEntity<List<Car>>(cars, HttpStatus.OK);
}

Modifing our sample json above we will convert it to a json array and add an additonal node. Lets make a request using advanced rest client chrome plugin and we should see the miles increment by 100.

[
  {
    "color":"Blue",
    "miles":200,
    "vin":"1234"
  },
  {
    "color":"Red",
    "miles":500,
    "vin":"1235"
  }
]

Passing multiple json objects

[3:25]

If you want to send multiple json objects to a controller, you will need to create a wrapper object that represents your request due to the request containing the entire JSON content. We will create a Truck object, a RequestWrapper object and a new @RequestMapping.

Truck object

public class Truck {

    private String VIN;
    private String color;
    private Integer miles;

    //...
}

RequestWrapper object

The RequestWrapper will contain a List of Cars and a single truck object.

public class RequestWrapper {
    
    List<Car> cars;
    Truck truck;

    //...
}

New @RequestMapping

@RequestMapping(value = "/carsandtrucks", method = RequestMethod.POST)
public ResponseEntity<RequestWrapper> updateWithMultipleObjects(
        @RequestBody RequestWrapper requestWrapper) {

    requestWrapper.getCars().stream()
            .forEach(c -> c.setMiles(c.getMiles() + 100));

    // TODO: call persistence layer to update

    return new ResponseEntity<RequestWrapper>(requestWrapper, HttpStatus.OK);
}

Making the request

Again, we will use advanced rest client to http://localhost:8080/carsandtrucks with the following JSON.

{
  "cars":[
    {
      "color":"Blue",
      "miles":100,
      "vin":"1234"
    },
    {
      "color":"Red",
      "miles":400,
      "vin":"1235"
    }
  ],
  "truck":{
    "color":"Red",
    "miles":400,
    "vin":"1235"
  }
}

Thanks for joining in today's level up lunch, have a great day.