1

I am trying to consume a POST restful service. When I try it on Postman I get succesful response. But when I try it on java with below code I am gettin response code 400. In postman I am pasting the same input with replacing escape characters.

try {

    URL url = new URL("https://localhost/PasswordVault/api/Accounts");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoOutput(true);

    conn.setRequestProperty("Content-Type", "application/json");
    String input = "{\"qty\":100,\"name\":\"iPad 4\", \"detail\":{\"ver\":\"2020\",\"productionDate\":\"2020\"}}";

    OutputStream os = conn.getOutputStream();
    os.write(input.getBytes());
    os.flush();


    if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
        throw new RuntimeException("Failed : HTTP error code : "
                + conn.getResponseCode());
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

    String output;
    System.out.println("Output from Server .... \n");
    while ((output = br.readLine()) != null) {
        System.out.println(output);
    }

    conn.disconnect();
} catch (Exception e) {
        System.out.println("Exception:- " + e);
}
Lutzi
  • 416
  • 2
  • 13
gakiris
  • 13
  • 1
  • 4

3 Answers3

1

I would highly recommend that you use a library for this. You can use Jackson, this greatly simplifies and standardizes java interaction with remote HTTP services.

Something along these lines will get you started:

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class ApiClient
{

    private transient Client client;
    protected transient WebTarget apiRoot;

    public ApiClient(String rootUrl) 
    {
        this.client = ClientBuilder.newBuilder().build();
        // The root URL is your API starting point, e.g. https://host/api
        this.apiRoot = client.target(rootUrl);
    }

    public Response doPostToAccounts(String data)
    {
        try 
        {
            // This is where you execute your POST request
            return apiRoot.path("/Accounts")
                .request(MediaType.APPLICATION_JSON)
                .post(Entity.entity(data, MediaType.APPLICATION_JSON));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

}
mvreijn
  • 2,807
  • 28
  • 40
  • Thank you for your response. I've tried your solution. I got "Server redirected too many times(20)" error. Than I searched it and I found adding ClientProperties.FOLLOW_REDIRECTS, false may have been resolve the problem but this time I am getting 301- Moved Permanently – gakiris Dec 14 '20 at 13:08
  • Did you pass `https://localhost/PasswordVault/api` as the rootUrl and `/Accounts` as the path? Typically 301 means it expects a / at the end. Also: the `Response` object will contain information about where it redirects you to. – mvreijn Dec 14 '20 at 13:22
  • Thank you for your caveat. As you mentioned, I copied url wrongly. After correction I am getting 400 Bad request again. I tried 3 different methods for calling the service. And getting same 400 response. I am pretty sure that there is something dfferent from the postman request. I will add what is extra in postman's header to my request. – gakiris Dec 14 '20 at 13:34
  • Keep in mind that a HTTP 400 error often means: the request body is not correct for the resource, or the content type is incorrect for the body. – mvreijn Dec 15 '20 at 20:25
0

Some ideas:

  • Encode your request post data in UTF-8: "post data".getBytes(StandardCharsets.UTF_8)
  • Read the response from the server (not just the code) to hopefully get more details on the problem (connection.getErrorStream())
  • Is there a missing authorization header? (an API token etc.)
  • Use single quotes to make your request data string more readable, or use a JSON library to avoid manual mistakes
  • also call OutputStream.close() after flush()

E.g.

  // handle error code
  if(connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
    // use getErrorStream for non OK statuses (https://stackoverflow.com/questions/613307/read-error-response-body-in-java)
    String errorMessage = "HTTP response code: " + responseCode
        + (responseMessage == null || responseMessage.trim().length() == 0 ? "" : " " + responseMessage);

    InputStream errorStream = connection.getErrorStream();
    if(errorStream != null) {
      String errorString = streamToString(connection.getErrorStream());
      if(errorString.length() > MAX_MSG_LENGTH) {
        errorString = errorString.substring(0, Math.min(MAX_MSG_LENGTH, errorString.length())) + "...";
      }
      errorMessage += ", HTTP response data: " + errorString;
    }

    throw new RuntimeException(errorMessage);
  }

  // handle OK code
  // ...
Reto Höhener
  • 5,419
  • 4
  • 39
  • 79
0

First, check the request headers that the postman may be sending and your code does not. You may need to add some headers to your request before sending it. Second, I strongly recommend to use some 3d party Http client library instead of coding your HTTP request on your own. Some well known libraries are Apache Http client and OK Http client. I personally use my own Http client that is part of a MgntUtils Open source library. You are welcome to try it as well. Here is simplified code just to demonstrate reading some response from a site:

    try {
        HttpClient client = new HttpClient();
        client.setConnectionUrl("https://www.yahoo.com/");
        String result = client.sendHttpRequest(HttpMethod.GET);
        System.out.println(result);
    } catch (IOException e) {
        System.out.println(TextUtils.getStacktrace(e, "com.mgnt."));
    }
    

But of course you could send POST requests and set Request headers and read textual or binaly response and response headers with this library as well. Here is a link to HttpClient class Javadoc. The library itself is available as Maven artifact and on Github, including Javadoc and source code

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
  • Thank you for your response. I tried with Apache HttpClien as you adviced. But I am still getting 400 Bad request response. – gakiris Dec 14 '20 at 13:10
  • So, check the response headers, you may find the reason why you get the error – Michael Gantman Dec 14 '20 at 14:21
  • Also, if you use my library, it automatically retrieves errorStream if an error code returns. So you may get some more additional info without extra-coding – Michael Gantman Dec 14 '20 at 14:36