Adding multiple headers while calling REST api via Jersey clients - java

I am trying to add multiple header. But failed miserably so far. I had tried lots of code tweaking but failed. Can someone help me fix the code or at least tell me what's wrong ?
Header mapping code:
Map<String, String> headers = new HashMap<String, String>();
headers.put("authorization", authToken);
headers.put("API-Version", apiVersion);
headers.put("Content-Type", MediaType.APPLICATION_JSON);
actual calling code:
String serviceUrl = serviceHostUrl;
Client client = Client.create();
WebResource webResource = client.resource(serviceUrl).path(path);
WebResource.Builder builder = webResource.getRequestBuilder();
if(headers != null && !headers.isEmpty()) {
for(Map.Entry<String, String> entry : headers.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
}
ClientResponse response = builder.post(ClientResponse.class, input);
UPDATE
if in second snippet I use below code instead of setting headers in loop, it works fine. That's really weird.
builder.header("authorization", "Basic SDFSFSDFSDFSDFSDFSDFSDF");
builder.header("API-Version", "5.2");
builder.header("Content-Type", MediaType.APPLICATION_JSON);

I think the issue here is, type of MAP that you are trying to access.
Map<String, Object> headers = new HashMap<String, Object>();
The WebSource builder accepts header(String,Object). So Try with changing the map type.

The header method does change the builder object. It creates a new object and the existing builder is not affected.
for(Map.Entry<String, String> entry : headers.entrySet()) {
builder = builder.header(entry.getKey(), entry.getValue());
}

Basic auth is like: Authorization = "Authorization" ":" credentials
an example
byte[] loginBytes = ("1" + ":" + "1").getBytes();
StringBuilder authString = new StringBuilder().append("Basic ")
.append(Base64.encodeToString(loginBytes, Base64.NO_WRAP));
_headers.put("Authorization", authString );

Related

Java 11: New HTTP client send POST requests with x-www-form-urlencoded parameters

I'm trying to send a POST request using the new http client api.
Is there a built in way to send parameters formatted as x-www-form-urlencoded ?
My current code:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(BodyPublishers.ofString("a=get_account&account=" + URLEncoder.encode(account, "UTF-8")))
.build();
What I'm looking is for a better way to pass the parameters. Something like this:
Params p=new Params();
p.add("a","get_account");
p.add("account",account);
Do I need to build myself this functionality or is something already built in?
I'm using Java 12.
I think the following is the best way to achieve this using Java 11:
Map<String, String> parameters = new HashMap<>();
parameters.put("a", "get_account");
parameters.put("account", account);
String form = parameters.entrySet()
.stream()
.map(e -> e.getKey() + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpResponse<?> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body().toString());
This way could be useful:
String param = Map.of("param1", "value1", "param2", "value2")
.entrySet()
.stream()
.map(entry -> Stream.of(
URLEncoder.encode(entry.getKey(), UTF_8),
URLEncoder.encode(entry.getValue(), UTF_8))
.collect(Collectors.joining("="))
).collect(Collectors.joining("&"));
You can use up to 10 pairs (param, value) by Map.of(...). It returns an unmodifiable map.
As Łukasz Olszewski said , worked correctly :
String params = Map.of(
Constants.PARAM_CLIENT_ID, apiObject.getClientId(),
Constants.PARAM_SCOPE, apiObject.getScope(),
Constants.PARAM_CODE, apiObject.getCode(),
Constants.PARAM_REDIRECT_URI, apiObject.getRedirectUri(),
Constants.PARAM_GRANT_TYPE, apiObject.getGrantType(),
Constants.PARAM_CODE_VERIFIER, apiObject.getCodeVerifier())
.entrySet()
.stream()
.map(entry -> Stream.of(
URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8),
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("="))
).collect(Collectors.joining("&"));
HttpResponse<?> response = utils.consumeHttpPostFormUrlEncodedClientByRequestUrl(Constants.URL_BASE + Constants.URL_GET_TOKEN, params);
and consumeHttpPostFormUrlEncodedClientByRequestUrl
public HttpResponse<?> consumeHttpPostFormUrlEncodedClientByRequestUrl(String url, String map) throws IOException, InterruptedException {
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
.header("Content-Type", String.valueOf(MediaType.APPLICATION_FORM_URLENCODED))
.POST(HttpRequest.BodyPublishers.ofString(map))
.build();
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}
Instead of Stream.of you can use more compact String.join (according to Łukasz Olszewski answer):
String form = Map.of("param1", "value1", "param2", "value2")
.entrySet()
.stream()
.map(entry -> String.join("=",
URLEncoder.encode(entry.getKey().toString(), StandardCharsets.UTF_8),
URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8)))
.collect(Collectors.joining("&"));
return HttpRequest.BodyPublishers.ofString(form);
Check out Methanol. It's got a nice FormBodyPublisher for x-www-form-urlencoded bodies.
var formBody = FormBodyPublisher.newBuilder()
.query("a", "get_account")
.query("account", account)
.build();
var request = MutableRequest.POST("https://example.com", formBody);
// Methanol implements an HttpClient that does nice things to your request/response.
// Here, the Content-Type header will be added for you.
var client = Methanol.create();
var response = client.send(request, BodyHandlers.ofString());

okhttp add post params from array

im trying to send post request with N numbers of params using okhttp3.
i can only find a way doing it with predefined number of params.
how can i dynamically add more params to the post request?
i want to loop over an array list of keys and values and add them to the addFormDataPart or any other equivalent method.
this is the current code:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("email", "your-email#email.com")
.addFormDataPart("name", "your-name")
.build();
Request request = new Request.Builder()
.url("url")
.post(requestBody)
.build();
use a Hash map
// HashMap with Params
HashMap<String, String> params = new HashMap<>();
// dynamically add more parameters like this:
params.put( "name", "Arom" );
params.put( "key_from_list", "value_from_list" );
// Initialize Builder (not RequestBody)
FormBody.Builder builder = new FormBody.Builder();
// loop while Adding Params to Builder
for ( Map.Entry<String, String> entry : params.entrySet() ) {
builder.add( entry.getKey(), entry.getValue() );
}
// Create RequestBody
RequestBody formBody = builder.build();
// Create Request (same)
Request request = new Request.Builder()
.url( "url" )
.post( formBody )
.build();

Creating a Bitbucket-Repository in Java via REST

I am trying to create a Bitbucket repository using their REST-API. Everything seems to work except setting the "parent" project, where the repository needs to be created in. On this link a cURL example is provided. In the body, the parameter "scm" is set as either "git" or "hg", both being Strings, the parameter "project" seems to be a json object containing a key-value pair. Everything I tried so far did not work (json object, string, etc.)
Question: How can I create a repository IN a specific project?
My code looks the following:
RestTemplate restTemplate = new RestTemplate();
String url = "https://api.bitbucket.org/2.0/repositories/" + tName + "/" + rName;
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic 1234567890qwert");
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
MultiValueMap<String, String> project = new LinkedMultiValueMap();
project.add("key", "aaaaaaaa"); //the repo should be created in the project aaaaaaaa
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
postParameters.add("scm", "hg"); //hg or git, does not matter
postParameters.add("project", project); //<-- the api ignores the declared project
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(body, headers);
ResponseEntity<BitbucketRepository> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, BitbucketRepository.class);
System.out.println("createRepository: " + response);
return response;
You could use the bitbucket-rest library to do this like so:
BitbucketClient client = BitbucketClient.builder()
.endPoint("http://127.0.0.1:7990")
.credentials("admin:password") // will base64 for you if not already done. Can optionally use token auth as well.
.build();
CreateRepository crepo = CreateRepository.create("my-repo", true);
Repository repo = client.api().repositoryApi().create("my-project", crepo);

Create a java REST client to call a spring boot REST API

I have a springboot project that takes only POST JSON String which I'm converting to HashMap using gson. I tested using Postman as a POST and add the body as props with a json string like {'fistname': 'John', 'lastname' : 'Doe'}, translates to props = {'fistname': 'John', 'lastname' : 'Doe'}. its working as expected
#RequestMapping(value = "/rest", method = RequestMethod.POST)
protected String parse(#RequestParam("props") String props) {
Gson gson = new Gson();
Map<String, String> params = new HashMap<String, String>();
params = gson.fromJson(props, Map.class);
// Rest of the process
}
On the other hand, I have a JavaEE project, which needs to call this API
protected void callREST() {
try {
String json = someClass.getDate() //retrieved from database which is stored as json structure
Map<String, String> props = gson.fromJson(json, Map.class);
URL url = new URL("http://localhost:9090/myApp/rest");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
DataOutputStream wr = new DataOutputStream( conn.getOutputStream());
System.out.println(props.toString());
wr.writeBytes(json.toString());
wr.flush();
wr.close();
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) {
//print stack trace
}
}
I get Failed :: HTTP error code : 400. I suspect the spring boot is not receiving the data in props variable since its a POST request.
What should i add in the client code to pass the props and the data to make this call successful ?
Note: JavaEE is running on tomcat :8080, Springboot is running on
different tomcat :9090
#RequestParam means that server awaits param in request URL http://localhost:9090/myApp/rest?param=..... but in you client you are writing JSON in body of request.
Try to use #RequestBody annotation in your endpoint
protected String parse(#RequestBody String props) {...}
Your resources expects to get form parameters (i.e. key value pairs, using x-www-form-urlencoded encoding), where the value happens to be JSON (although what you posted is not valid JSON).
But your client Java code sets the content type to application/json, and sends the JSON as the body, instead of sending it as the value of the key "props" of a x-www-form-urlencoded body.
So that can't work.
If you can change the server, then do that. Accept JSON as the body directly:
#RequestMapping(value = "/rest", method = RequestMethod.POST)
public String parse(#RequestBody Map<String, String> map) {
...
}
If not, you'll need to send the correct key value pair, and make sure the value is properly url-encoded.

Using the Jersey client to do a POST operation

In a Java method, I'd like to use a Jersey client object to do a POST operation on a RESTful web service (also written using Jersey) but am not sure how to use the client to send the values that will be used as FormParam's on the server. I'm able to send query params just fine.
Not done this yet myself, but a quick bit of Google-Fu reveals a tech tip on blogs.oracle.com with examples of exactly what you ask for.
Example taken from the blog post:
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("name1", "val1");
formData.add("name2", "val2");
ClientResponse response = webResource
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.post(ClientResponse.class, formData);
That any help?
Starting from Jersey 2.x, the MultivaluedMapImpl class is replaced by MultivaluedHashMap. You can use it to add form data and send it to the server:
WebTarget webTarget = client.target("http://www.example.com/some/resource");
MultivaluedMap<String, String> formData = new MultivaluedHashMap<String, String>();
formData.add("key1", "value1");
formData.add("key2", "value2");
Response response = webTarget.request().post(Entity.form(formData));
Note that the form entity is sent in the format of "application/x-www-form-urlencoded".
It is now the first example in the Jersey Client documentation
Example 5.1. POST request with form parameters
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:9998").path("resource");
Form form = new Form();
form.param("x", "foo");
form.param("y", "bar");
MyJAXBBean bean =
target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE),
MyJAXBBean.class);
If you need to do a file upload, you'll need to use MediaType.MULTIPART_FORM_DATA_TYPE.
Looks like MultivaluedMap cannot be used with that so here's a solution with FormDataMultiPart.
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileNameToUpload);
FormDataMultiPart part = new FormDataMultiPart();
part.field("String_key", "String_value");
part.field("fileToUpload", stream, MediaType.TEXT_PLAIN_TYPE);
String response = WebResource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, part);
Simplest:
Form form = new Form();
form.add("id", "1");
form.add("name", "supercobra");
ClientResponse response = webResource
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.post(ClientResponse.class, form);
Also you can try this:
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("name1", "val1");
formData.add("name2", "val2");
webResource.path("yourJerseysPathPost").queryParams(formData).post();

Categories

Resources