javaspring-bootrestokhttp

OkHttp Response doesn't have provided body object on the client side


I am writing REST APIs using okhttp library in Spring Boot. I have my OkHttpClient requesting a GET request(client) from another API(server). Both the client and server uses OkHtttp libraries, so I had used okhttp.response to return an object from Server. On the server side I was able to properly print the body inside the Response object where as on the client side I don't see the expected object in the client's Response object.dd

Client side:

OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("http://localhost:8081/temp/getResponse2")
        .build();
Response response = httpClient.newCall(request).execute();
final String body = response.body().string();
response.body().close();
System.out.println("The response is: " + response.toString());
System.out.println("The body in response is: " + body);
return body;

Server side(API):

@GetMapping(path = "/temp/getResponse2")
    public Response testGETAWBNotes2() throws IOException {
        final ABNotes abNotes = ABNotes.builder()
                .name("name")
                .remarks("remarks")
                .build();
//        return new ResponseEntity<>(awbNotes, HttpStatus.OK);
        Request request = new Request.Builder()
                .url("https://www.google.com")
                .build();
        okhttp3.ResponseBody responseBody = okhttp3.ResponseBody.create(objectMapper.writeValueAsString(abNotes),
                MediaType.parse("application/json; charset=utf-8"));
        Response response = new Response.Builder()
                .request(request)
                .body(responseBody)
                .protocol(Protocol.HTTP_1_1)
                .message("Success")
                .code(200)
                .build();
        System.out.println("the body is: " + response.body().string());
        response.body().close();
        return response;
    }

On the server side the body has object:
"the body is: {"name":"name","remarks":"remarks"}"
Where as on the client side I see the body object as:
"The body in response is: {"lazyCacheControl$okhttp":null,"redirect":false,"successful":true}"

But when I used RepsonseEntity<Object> to return the ABNotes object from Server side, I was able to see the ABNotes object on the client side but that's not the case when I return ohttp.Response from the server side.

An another question is: What should be the request object that we have to put in the Response Body? If our API doesn't take any inputs from client, what request should we put in Response in this case, does placing a dummy request object works?

I was not able to find any useful server side Response Building example paired with client side code example. Any thoughts or suggestions on where am I making a mistake here?

Thanks in advance.


Solution

  • In the server code, you are constructing an OkHttp Response object manually and returning it from a Spring controller. This isn't the typical use case for Spring Boot, as Spring expects you to return domain objects or ResponseEntity<?> objects, which it then serializes into JSON (or another format, depending on configuration) and wraps it in an HTTP response.

    When you manually create and return an OkhHttp Response, Spring Boot does not serialize the response body into JSON but instead treats the Response object itself as the response body. This is why you see JSON representations of the internal fields of the Response object itself ("lazyCacheControl$okhttp": null,"redirect": false,"successful": true) on the client side rather than the expected JSON data.

    To solve this issue and align with typical Spring Boot practices, you should return a domain object or a ResponseEntity directly from your server endpoint:

    @GetMapping(path = "/temp/getResponse2")
    public ResponseEntity<ABNotes> testGETAWBNotes2() throws IOException {
        ABNotes abNotes = ABNotes.builder()
            .name("name")
            .remarks("remarks")
            .build();
        return new ResponseEntity<>(abNotes, HttpStatus.OK);
    }
    

    In your client-side code, I'd recommend adding a try-with-resources block to ensure that the response body is closed after you're done using it. This is a best practice to avoid leaking resources.

    try (Response response = httpClient.newCall(request).execute()) {
        final String body = response.body().string();
        System.out.println("The body in response is: " + body);
        return body;
    } catch (IOException e) {
        // Handle the error appropriately
    }