Jersey 2.x: How to add Headers on RESTful Client - java

I've already looked at How to add Headers on RESTful call using Jersey Client API, however this is for Jersey 1.x.
How do I set a header value (such as an authorization token) in Jersey 2.21?
Here is the code I'm using:
public static String POST(final String url, final HashMap<String, String> params)
{
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target(url);
String data = new Gson().toJson(params);
Entity json = Entity.entity(data, MediaType.APPLICATION_JSON_TYPE);
Invocation.Builder builder = target.request(MediaType.APPLICATION_JSON_TYPE);
return builder.post(json, String.class);
}

In Jersey 2.0+, you can register a custom implementation of ClientRequestFilter that can manipulate the headers in the request that the Client API will send out.
You can manipulate the headers via the ClientRequestContext parameter that is passed into the filter method. The getHeaders() method returns the MultivaluedMap on which you can put your header(s).
You can register your custom ClientRequestFilter with your ClientConfig before you call newClient.
config.register(MyAuthTokenClientRequestFilter.class);

If you want to add only few headers in Jersey 2.x client, you can simply add it when request is sending as follows.
webTarget.request().header("authorization":"bearer jgdsady6323u326432").post(..)...

To add to what Pradeep said, there's also headers(MultivaluedMap < String, Objects> under WebTarget.request() if you have a gaggle of headers:
MultivaluedMap head = new MultivaluedHashMap();
head.add("something-custom", new Integer(10));
head.add("Content-Type", "application/json;charset=UTF-8");
builder.headers ( head ); // builder from Joshua's original example

Related

AWS Appsync Graphql Java Client - IAM authorisation

This is the schema for which I have implement business logic
type Query {
getLicenseInformation(localmd5: String): License #aws_cognito_user_pools
getUserInformation(username: String!): CognitoUser #aws_iam
listUsers(searchString: String): [NamedResource] #aws_iam
}
I use RestTemplate as my Java client to consume graphql endpoint giving API key as authorization. I ad dthe api key in the header paart as x-api-key.
RestTemplate restTemplate=new RestTemplate();
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("x-api-key",api_key.getId());
requestHeaders.set("Content-Type","application/graphql");
HttpEntity entity = new HttpEntity(requestHeaders);
ResponseEntity<String> exchange = restTemplate.exchange(URL, HttpMethod.POST, new HttpEntity(query,requestHeaders),String.class);
The above implementation retrieves the values from the backend.
But according the schema which is defined by the other team, the authorization mode is not API key rather iam. So I have to configure the rest template accordingly.
Where in the Client side code in Java I can configure so that aws_iam is used as authorization method to retrieve the information from the endpoint. Dynamodb is the datasource
Building the request object like below helps:
private DefaultRequest prepareRequest(HttpMethodName method, InputStream content) {
Map<String,String> headers = new HashMap<>();
headers.put("Content-type", "application/json");
headers.put("type", "AUTH_TYPE.AWS_IAM");
headers.put("X-Amz-Security-Token",securityToken);
DefaultRequest request = new DefaultRequest(API_GATEWAY_SERVICE_NAME);
request.setHttpMethod(method);
request.setContent(content);
request.setEndpoint(this.endpoint);
request.setHeaders(headers);
return request;
}

(Android+Retrofit 2) - Is there a drawback on the usage of Static Headers with Interceptors?

Let's say I have 5 API endpoints and 4 of them require the #Header "Authorization"; the other one doesn't.
Is there a drawback or anything of the sort when I use an Interceptor to insert the header for all API calls even though one of the endpoints does not require it? :)
Probably would be better use a more customizable approach that's retrofit2 provides - dynamic headers. A dynamic header is passed like a parameter to the method. The provided parameter value gets mapped by Retrofit before executing the request. Example:
#GET("/yourEndpoint")
Call<List<Obj>> getSomth(#Header("Your-Header") String yourHeader);
But if you only worrying about extra header passing, I don't see any drawback in your particular case.
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
Request request = chain.request();
if (!request.url().toString().contains("/tapi/login/login")) {
String cookie = SharedObj.getCookie();
builder.addHeader("Cookie", cookie);
}
return chain.proceed(builder.build());
}
This is my solution.All api need cookie except login api('/tapi/login/login') ,So I judge url to decide to wether to add cookie in request.
There is no problem using Interceptor with header for all API.
Set headers in interceptors and use to all API. If the API method is with or without auth it will be worked.
Like this - Create ones, use everywhere.
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
//Add headers here using requestbuilder.
String authToken =//Your Authtoken
if (authToken != null)
requestBuilder.header("Authorization", authToken);
requestBuilder.method(original.method(), original.body());
return chain.proceed(requestBuilder.build());
});
In Retrofit
Retrofit retrofit= new Retrofit.Builder().baseUrl("baseUrl").client(httpClient.build()).build();

Send JSON body but with ContentType=application/x-www-form-urlencoded with ClientBuilder

I know the question is weird. Unfortunately I have a service that requires everything to have the header ContentType=application/x-www-form-urlencoded, eventhough the body is JSON
I am trying to use JAX-RS 2.0 ClientBuilder to call it:
String baseUrl = "http://api.example.com/";
JSONObject body = new JSONObject();
body.put("key", "value");
Client client = ClientBuilder.newClient();
client.register(new LoggingFilter());
Builder builder = client.target(baseUrl).path("something").request();
Invocation inv = builder
.header("Content-type", MediaType.APPLICATION_FORM_URLENCODED)
.buildPost(Entity.json(body));
Response response = inv.invoke();
int status = response.getStatus();
// I get 415, unsupported media type (in this case is unexpected)
I have checked my logs and I eventhough I am setting application/x-www-form-urlencoded (via the MediaType) the request appearantly has the Content-type of application/json
How can I force the request to have the Content-type I want?
BTW: This is my custom logger:
public class LoggingFilter implements ClientRequestFilter {
private static final Logger LOG = Logger.getLogger(LoggingFilter.class.getName());
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
LOG.log(Level.INFO, "body");
LOG.log(Level.INFO, requestContext.getEntity().toString());
LOG.log(Level.INFO, "headers");
LOG.log(Level.INFO, requestContext.getHeaders().toString());
}
}
And these are the logs I get:
com.acme.LoggingFilter I body
com.acme.LoggingFilter I {"key":"value"}
com.acme.LoggingFilter I headers
com.acme.LoggingFilter I {Content-type=[application/json]}
The problem with trying to use one of the static Entity helper methods is that it overrides any previous Content-Type header you may have set. In your current case, Entity.json automatically sets the header to application/json.
Instead of using the .json method, you can just use the general purpose Entity.entity(Object, MediaType) method. With your current case though, you can just do Entity.entity(body, MediaType.APPLICATION_FORM_URLENCODED_TYPE) though. The reason is that the client will look for a provider that knows how to serialize a JSONObject to application/x-www-form-urlencoded data, which there is none. So you will need to first serialize it to a String. That way the provider that handles application/x-www-form-urlencoded doesn't need to serialize anything. So just do
Entity.entity(body.toString(), MediaType.APPLICATION_FORM_URLENCODED_TYPE);

How to send request parameters with same parameter-name

This question is an extension to How do I set params for WS.post() in play 2.1 Java
My web service request handler is as follows
#POST
#Path("/requestPath")
public String addChallengersToLeague(
#FormParam("name") String name,
#FormParam("values") List values);
since WSRequestHolder accepts a Map<String, String> in setQueryParameter method, I am not able to send parameter list with same name.
I can send request from POSTMAN with multiple parameters having name 'values'and it works fine.
Can you suggest how to do the same using play? I am using play 2.1.3
Thanks in advance.
This can be done using play.libs.WS.WSRequest API
Following is a simple example
WSRequest request = new WSRequest("<Method>"); //Method can be GET, POST etc
request.setUrl("<service-url>");
request.setHeader("Content-Type", "application/x-www-form-urlencoded");
com.ning.http.client.FluentStringsMap map = new com.ning.http.client.FluentStringsMap();
map.add("name", "aniket");
Set<String> values= new HashSet<String>();
values.add("1");
values.add("2");
values.add("3");
values.add("4");
map.add("values", values);
request.setQueryParameters(map);
Promise<Response> response = request.execute();
You can then use response.get().getBody() to get response body.

Need Jersey client api way for posting a webrequest with json payload and headers

I am writing a client for one of my REST API using jersey(org.glassfish.jersey.client.*).
api url is : http://localhost:5676/searchws/search/getresults (POST)
this api returns a json response. i need to provide a payload using jersey client and thats where i am stuck. FOllowing is a sample extract of payload which i need to provide (preferably as string)
Question is how can i provide a payload (XML/JSON) as string or entity to my webtarget.
I saw the answer to providing payload mentioned by calden How to send Request payload to REST API in java? but i am looking for a way to do it in jersey client.
Here is my code till now which does not work fully for post requests.
public class RequestGenerator
{
private WebTarget target;
private ClientConfig config;
private Client client;
private Response response;
public RequestGenerator(Method RequestSendingMethod) throws Exception
{
switch (RequestSendingMethod)
{
case POST :
config = new ClientConfig();
client = ClientBuilder.newClient(config);
target = client.target("http://localhost:5676/searchws").path("search").path("getresults");
String payload = "{\"query\":\"(filter:(\\\"google\\\")) AND (count_options_availbale:[1 TO *])\"}"; //This is just a sample json payload actual one is pretty large
response = target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json("")); // What to do here
String jsonLine = response.readEntity(String.class);
System.out.println(jsonLine);
}
}
You specify payload as the argument to Entity.json
String payload = "{\"query\":\"(filter:(\\\"google\\\")) AND (count_options_availbale:[1 TO *])\"}";
response = target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(payload));
I got this working using following code, Salil's code works fine as well(+1 with thanks to him), thanks everyone who contributed to this problem, loving stackoverflow:
public class RequestGenerator
{
private WebTarget target;
private ClientConfig config;
private Client client;
private Response response;
public RequestGenerator(Method RequestSendingMethod) throws Exception
{
switch (RequestSendingMethod)
{
case POST :
String payload = "\r\n{\r\n\"query\": \"google \",\r\n\"rows\": 50,\r\n\"return_docs\": true,\r\n\"is_facet\": true\r\n}"; //this is escapped json string in single line
config = new ClientConfig();
client = ClientBuilder.newClient(config);
target = client.target("http://localhost:7400/searchws/search/getresults");
response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(payload, MediaType.APPLICATION_JSON), Response.class);
processresponse(response); //This could be any method which processes your json response and gets you your desired data.
System.out.println(response.readEntity(String.class));
break;
case GET :
config = new ClientConfig();
client = ClientBuilder.newClient(config);
target = client.target("http://localhost:7400/search-service/searchservice").path("search").path("results").path("tiger");
response = target.request().accept(MediaType.APPLICATION_JSON).get();
processresponse(response); //This could be any method which processes your json response and gets you your desired data.
System.out.println(response.readEntity(String.class));
}
}

Categories