Spring MVC RestFul service + Jersey Client 400 Bad Request - java

I have created a RESTful webservice in Spring, and am trying to call it via a Jersey client. Here's my Controller method
#RequestMapping(value = "/create",
method = RequestMethod.POST,consumes={MediaType.APPLICATION_JSON_VALUE},
produces={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<User> createUser(#RequestBody User user ){
User u = null;
HttpStatus statusCode;
try{
userService.create(user);
u = userService.getUserById(user.getId());
statusCode = HttpStatus.CREATED;
}catch(Exception e){
logger.error("Could not create user ", e);
u = null;
statusCode = HttpStatus.CONFLICT;
}
return new ResponseEntity<User>(u, statusCode);
}
When I call this web service from a Jersey client, I get 400 Bad Request error. Here's the client that calls this service
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("xxxx", "yyyy");
final Client client = ClientBuilder.newClient();
client.register(feature);
WebTarget webTarget = client.target("http://localhost:8080/MyWeb/api").path("user/create");
Form form = new Form();
form.param("id", "jersey");
form.param("firstName", "Jersey");
form.param("lastName", "Client");
/*User user = webTarget.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), User.class);*/
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON_TYPE);
Response response = invocationBuilder.post(Entity.entity(form, MediaType.APPLICATION_JSON_TYPE));
System.out.println(response.getStatus());
System.out.println(response.getStatusInfo());
I tried playing around with the MediaType values in both the service as well as the client, but nothing works.
I've to tell you that I'm totally new to this and this is like my first stint at RESTful web services.
Please help me understand what mistake I'm doing..

I think you are telling to the service you are sending JSON in the payload, but you are sending form params instead, when you do:
form.param("id", "jersey");
and the following lines, you are emulating a POST just like creating an HTML Form with submission button.
You may have to declare a class User in your client, instance one object of this class and fill the properties as:
User user = new User();
user.setId("jersey");
and then send this object in the POST (i haven't work with Invocation.Builder but it sure have some post method with an object as parameter), Jersey client should take care of the serialization sending the JSON string in the payload.

Related

create a Rest API with customized header request

I'm falling into a problem this morning with a custom request between two application, what i need to do is to let application able to talk eachother with two Rest API cause i need to do some actions on the first application by the second. The two applications are developed with springboot.
Suppose to call this two applications admin and superadmin
superadmin send a request with a RestAPI and a customized header -> name = key value = 1234
admin recieve the request and first of all check if the header is present or not, after that the header is finded it can proceed to do all the task.
Here's the code that i've developed :
SUPERADMIN :
#PostMapping(value="/test_api_header")
public ResponseEntity<String> test_API(#RequestParam String url) {
RestTemplate template = new RestTemplate();
URI targetUrl = UriComponentsBuilder.fromUriString(url) // Build the base link
.path("/test_API") // Add path
.build() // Build the URL
.encode() // Encode any URI items that need to be encoded
.toUri(); // Convert to URI
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-Type", "application/json");
headers.add("superadminKey", "123456abc");
// build the request
ResponseEntity<String> entity = template.exchange(targetUrl, HttpMethod.GET, new HttpEntity<String>(headers), String.class);
return entity;
}
ADMIN :
#Value("123456abc")
private String saKey;
#GetMapping(value = "/superadmin/test_API")
public String test_API(HttpServletRequest request) {
if (request.getHeader("superadminKey") == saKey) {
return "Finally";
} else {
return "Nothing to do, header not present";
}
}
The SUPERADMIN is able to communicate with the RESTApi in the ADMIN application, in fact on postman i received the answer : Nothing to do, header not present, but i really cannot be able to set that customized header in the superadmin request cause i cannot found it also on postman request in the section "headers".
I've seen that i could also create a customized API Key for this special case, but really don't know how it works, if someone could help me I would be very grateful!

How to consume a HTTPS GET service with Spring Boot

I am trying to consume the following HTTPS endpoints from Yahoo Weather Service:
Yahoo Weather Service API
I am doing some special query according to the API to get the current weather at some parametrized location.
#Service("weatherConditionService")
public class WeatherConditionServiceImpl implements WeatherConditionService {
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public WeatherCondition getCurrentWeatherConditionsFor(Location location) {
RestTemplate restTemplate = new RestTemplate();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(URL);
stringBuilder.append("?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22");
// TODO: Validate YQL query injection
stringBuilder.append(location.getName());
stringBuilder.append("%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys");
WeatherQuery weatherQuery = restTemplate.getForObject(stringBuilder.toString(), WeatherQuery.class);
// TODO: Test Json mapping response
Condition condition = weatherQuery.getQuery().getResults().getChannel().getItem().getCondition();
return new WeatherCondition(condition.getDate(), Integer.parseInt(condition.getTemp()), condition.getText());
}
Location is a class that provides the attribute "name" that is a String description of the location, such as "New York" or "Manila".
Condition an other classes just map the returning object.
When executing I get the following HTTP response:
org.springframework.web.client.HttpClientErrorException: 403 Forbidden
So this means I am not authorized to access the resource from what I understand.
The URL works great if I just copy & paste it in a web browser:
Yahoo Weather Query
I think that mapping is not a problem since I am not getting "400" (Bad Request) but "403" (Forbidden)
There must be some error on the way I use the RestTemplate object. I am researching but I can't find an answer.
The docs say you need an api key. But when I make a call like this:
fetch('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
.then(resp=> resp.json())
.then((res)=>console.log(res.query.results))
https://repl.it/NeoM
It works fine without one. Perhaps you've been blackisted for hitting the api too often.
Your code seems fine.
I finally found the answer. It finally WAS a Bad Request because I needed to pass the parameters differently (not as part of the URL).
I found the answer here. Here goes the code for my particular Yahoo Weather API call return a String (I still will have to do some work to use the mapping).
private static final String URL = "http://query.yahooapis.com/v1/public/yql";
public String callYahooWeatherApi() {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(URL)
.queryParam("q", "select wind from weather.forecast where woeid=2460286")
.queryParam("format", "json");
HttpEntity<?> entity = new HttpEntity<>(headers);
HttpEntity<String> response = restTemplate.exchange(
builder.build().encode().toUri(),
HttpMethod.GET,
entity,
String.class);
return response.getBody();
}

Issue creating repository github v3 api via Java

I'm trying to send a post request to github to create a repository. I've got oauth 2.0 working and the request is correctly signed but github is just returning "Problems parsing JSON"
I'm using Scribe for the oauth side of things and as far as I can tell I've added JSON to the URL but I'm not 100% certain I'm doing it correctly, or am I just missing headers or something?
#POST
#Path("create_repo/{userid}")
#Produces(MediaType.APPLICATION_JSON)
public Response createRepo(#PathParam("userid") String userid) {
OAuthService service = createService().build();
User user = collection.findOneById(userid);
final OAuthRequest request = new OAuthRequest(Verb.POST, "https://api.github.com/user/repos", service);
Token token = new Token(user.getGithubToken(), "SECRET");
service.signRequest(token, request);
request.addHeader("Content-type", "application/vnd.github.v3+json");
request.addHeader("X-OAuth-Scopes", "repo");
request.addQuerystringParameter("name", "Test_v1");
LOGGER.info("Built request: " + request.getCompleteUrl());
final com.github.scribejava.core.model.Response response = request.send();
return Response.ok(response.getBody()).build();
}
The built URL looks like: https://api.github.com/user/repos?access_token=XXX_SECRET_XXX&name=Test_v1
I've also tried swapping the access_token after the params but same result.
Appreciate the any help.
Well I solved this by creating a object, serializing it, and adding it as a payload.
#POST
#Path("create_repo/{userId}/{projectId}")
#Produces(MediaType.APPLICATION_JSON)
public Response createRepo(#PathParam("userId") String userId, #PathParam("projectId") String projectId) {
// Setup collections
User user = userCollection.findOneById(userId);
ProjectDescription projectDescription = projectCollection.findOneById(projectId);
// Build repository object from project description
GithubRepository repository = new GithubRepository();
repository.setName(projectDescription.getTitle());
repository.setDescription(projectDescription.getDescription());
// Serialize object
ObjectMapper mapper = new ObjectMapper();
String jsonInString = null;
try {
jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(repository);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// Build request
OAuthService service = createService().build();
final OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL + "/user/repos", service);
request.addHeader("content-type", "application/json");
request.addPayload(jsonInString);
// Sign and send request
Token token = new Token(user.getGithubToken(), "secret");
service.signRequest(token, request);
request.send();
return Response.status(201).build();
}
However, I'd still like to know where I went wrong with my first attempt.
Query string parameters are ignored in POST requests. That's why it worked when passing them in the request body.
From GitHub's API Overview docs:
Parameters
Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:
curl -i "https://api.github.com/repos/vmg/redcarpet/issues?state=closed"
In this example, the ‘vmg’ and ‘redcarpet’ values are provided for the :owner and :repo parameters in the path while :state is passed in the query string.
For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL should be encoded as JSON with a Content-Type of ‘application/json’:
$ curl -i -u username -d '{"scopes":["public_repo"]}' https://api.github.com/authorizations

XMLHttpRequest and JAX-RS 404 403 errors, can't get a response from javascript

Java EE is hell. I'm trying to implement a RESt service that is going to be queried by clients from arbitrary domain, using javascipt XMLHttpRequest.
For the server side, my context root is "qwerty". Then my resource class is:
#Path("test")
public class TestRest{
#GET
#Path("/{msg}")
#Consumes("text/plain")
#Produces("text/plain")
public Response answerBackToClient(#PathParam("msg") String message){
Response.ResponseBuilder r;
r = Response.ok();
r = r.header("Access-Control-Allow-Origin", "*");
r = r.entity("responce back to client: " + message);
return r.build();
}
}
So from any browser anywhere now, with javascript:
var x = new XMLHttpRequest();
x.open("get", "http://www.pathtoserver.com:8080/qwerty/test/someMessage/", true);
x.setRequestHeader("Content-Type", "text/plain");
x.send("something");
Deployed on GlassFish4, EE7, NetBeans7.4
After i invoke the send() method on the client side (javascript), i get a 404 error or 403 error. What is the simplest possible example that will solve this problem?

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