Skip to content
Advertisement

Webclient sending request body with get request

I have a spring-boot project called carrental-crud with an h2 memory database, and I want to access one of the endpoints from another project called carrental-api.

I use webClientBuilder for this on my other endpoints, but it is throwing status 500 with bad request when I try using it in postman.

I use JPArepository to access the h2 db with a query, this is how my orderRepository looks :

@Transactional
@Query(nativeQuery = true,value = "select count(*) from TBL_ORDER WHERE CUSTOMER_ID=?1")
public int getTotalOrders(long customerId);

Then in my adminCustomerService class, I use it like this :

public int getTotalOrders(long customerId) {
    loggerService.writeLoggerMsg("LISTED TOTAL ORDERS FOR A CUSTOMER");
    
    return orderRepository.getTotalOrders(customerId);
}

And then in my adminCustomerController :

@GetMapping(path = "/totalorders")
public int getTotalOrders(@RequestBody Customer customer) {
    return adminCustomerService.getTotalOrders(customer.getCustomerId());
}

and in my postman request body, I write :

{
  "customerId": 2
}

This works in my carrental-crud, but how can I recreate this in my carrental-api?

And using the same request body in postman, but I keep getting the error status 500 with bad request

EDIT : I managed to get this to work by using parameters instead of a request body.

This is how my adminCustomerService looks :

public int getTotalOrders(long customerId) {
   int orders = webClientBuilder.build()
            .get()
            .uri("http://localhost:8081/crud/v1/totalorders/" + customerId)
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<Integer>() {})
            .log()
            .block();
    return orders;
}

And my adminCustomerController :

@GetMapping(path = "/totalorders/{customerId}")
public int getTotalOrders(@PathVariable long customerId) {

    return adminCustomerService.getTotalOrders(customerId);
}

Advertisement

Answer

The issue is that you are simply sending customerId as a Long in your programmatic call when you should be sending something like the JSON that you showed. The simplest way to solve this is by creating a class that matches such JSON structure:

public class CustomerRequest {
    private long customerId;

    public CustomerRequest(long customerId) {
        this.customerId = customerId;
    }

    public long getCustomerId() {
        return customerId;
    }
}

And then you need to create an instance of such class when calling the API as follows:

public Flux<Integer> getTotalOrders(long customerId) {
    loggerService.writeLoggerMsg("LISTED TOTAL ORDERS FOR A CUSTOMER");

    return ((RequestBodySpec) webClientBuilder
            .build()
            .get()
            .uri("localhost:8081/crud/v1/totalorders"))
            .body(Flux.just(new CustomerRequest(customerId)), CustomerRequest.class)
            .retrieve()
            .bodyToFlux(Integer.class);
}

Still, I would suggest you having a more RESTful approach in your endpoint and use path parameter instead of a request body in a GET request. Something along the following lines:

@GetMapping(path = "/customers/{customerId}/total-orders")
public int getTotalOrders(@PathVariable long customerId) {
    return adminCustomerService.getTotalOrders(customerId);
}

Then you would make a request to this endpoint as follows:

public Flux<Integer> getTotalOrders(long customerId) {
    loggerService.writeLoggerMsg("LISTED TOTAL ORDERS FOR A CUSTOMER");

    return webClientBuilder
            .build()
            .get()
            .uri("localhost:8081/crud/v1/customers/{customerId}/total-orders", customerId))
            .retrieve()
            .bodyToFlux(Integer.class);
}

I would suggest you read the following online resources:

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement