jersey (JSR-311), how to implement #POST in container pattern - java

From NetBeans, I created a new REST webservice (using jersey), using the built-in wizards. in the container resource class, it created a stub,
#POST
#Consumes("application/json")
#Produces("application/json")
public Response postJson(Identity identity) {
identities.addIdentity(identity);
return Response.status(Status.OK).entity(identity).build();
}
how to i POST to this? my understanding is that in need to post name=val pairs. what's jersey expecting here? how would i post json to this using say curl? here's what i tried,
#!/bin/bash
DATA="{ \"id\": \"$1\", \"vcard\": \"$2\", \"location\": { \"latitude\": \"$3\", \"longitude\": \"$4\" } }"
echo "posting: $DATA"
HEADER='Content-Type:application/json'
URL='http://localhost:8080/contacthi-proximity-service/resources/is'
curl --data-binary "${DATA}" -H "${HEADER}" "${URL}"
when I post this, and look at the identity object coming in, all fields are null? I suspect my json is incorrect. when i manually add an object to my container, then form a get, I see this result,
{"identities":{"id":"Foo Bar","vcard":"VCARD123","location":{"latitude":"-1.0","longitude":"-1.0"}}}
when I try to post the same thing, all fields all null. I also tried,
{"id":"Foo Bar","vcard":"VCARD123","location":{"latitude":"-1.0","longitude":"-1.0"}}
same result.

To send requests to this method using curl, you would have to use something like:
HEADER='--header Content-Type:application/json'
URL='http://localhost:<port>/methodName'
curl --data-binary request.json ${HEADER} ${URL} -D response.txt
You can pass a string to the method. Above code will pick json string from the file mentioned. Sample json could be:
{"userName":"test","timestamp":"2010-08-05T11:35:32.982-0800","userId":"0982"}
For creating response you can use something like:
return Response.status(Status.OK).entity(responseString).build();
Classes used are:
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

Related

Getting the 307 Redirection Response instead of the target-location page content from an enpoint in Spring Boot

So I have a simple endpoint in my Spring Boot App, which just redirects to another website:
#Controller
public class FeedbackController {
#GetMapping(path = "/test")
public Mono<ResponseEntity<Void>> method() {
String redirectUrl = "https://www.google.com";
return Mono
.just(ResponseEntity.status(HttpStatus.TEMPORARY_REDIRECT).location(URI.create(redirectUrl)).build());
}
Making a GET request to this endpoint (e.g. in browser or with postman) gives me the page content of google as a response. However for testing purposes I want to make sure that the response is a TEMPORARY_REDIRECT with www.google.com as the Location Header.
How can I make a request to this endpoint so that the response is the 307 TEMPORARY_REDIRECT instead of the 200 with page content from the target website?
First
to test if its working, you could use simple tools like curl :
We add the -L flag to tell curl that we want to know if we are getting redirected
curl -L http://www.....
Go further
Then, you could simply use tools like MockMvc to automate this test
See this SO post

Method Not Allowed REST Java when trying to do POST

I just want to create a simple REST service and it uses #GET and #POST.
for the #GET function, everything is ok but for #POST, when I want to create a new user on my server the browser just keeps sating (METHOD NOT ALLOWED).
I read so many articles about how to fix this error but I haven't got anything yet.
My code for #POST :
#Path("/hello")
public class HelloResource(){
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("/post")
public Response createUser(#PathParam("name") String name,#PathParam("address") String address,#PathParam("birthYear") String birth,#PathParam("ps") String password) throws NotAllowedException,MethodNotFoundException,Exception {
DataStore.getInstance().putPerson(new Person(name, address, Integer.parseInt(birth), password));
String json = "{\n";
json += "\"status\": " + '"'+"CREATED" +'"'+ ",\n";
json+="}";
return Response.status(200).entity(json).build();
}}
I also tried adding #Consumes function with (MediaType.APPLICATION.JSON) and (MediaType.TEXT_PLAIN) but nothing changed.
Also the URL I enter for posting is :
http://localhost:8080/HelloREST/rest/hello/post?name=PouYad&address=mustbejsonlater&birthYear=2005&ps=12345
As you see I also tried so many exception handlers.
Can someone please help?
if you enter your URL in the browser URL address field, it won't work because the browser will send a "GET" request. So you must use a client that will allow you to send a "POST" like PostMan. Or write your own small httpConnection function that sends a "POST"
You also have to change the #PathParam to #FormParam for it to work (#QueryParam will also work, but because it is POST, it is best to use #FormParm).
Access URL directly through browser can only create Get Request, not POST Request
You should
Create HTML Form, set the action to your service url with POST method, and then submit it.
Use Rest Client like postman to access your service with POST method.
Write your own Http Client using java.net.http api or just simply use
one of the handy libraries/frameworks (Like Spring has RestTemplate).

CSV on RequestBody using Spring

I need to receive a csv file on the request and process it.
#PostMapping(value = "/csv", consumes = "text/csv")
public ViewObject postCsv(#RequestBody InputStream request){
// do stuff
}
But when I execute:
curl -X POST -H 'Content-Type: text/csv' -d #input.csv http://localhost:8080/csv
This is what shows up on my console:
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/csv;charset=UTF-8' not supported]
Spring is saying my request is invalid before anything else.
So, the question is: How to properly receive this csv?
As someone mentioned in comments, one approach is to implement your own HttpMessageConverter - there are examples of varying quality available on the web.
Another option if you already have some code for parsing CSVs using Spring's org.springframework.core.io.Resource classes is to change your method signature as follows to use Spring's built in ResourceHttpMessageConverter:
#PostMapping(path = "/csv", consumes = "application/octet-stream")
public ViewObject postCsv(#RequestBody Resource resource){
// do stuff
}

Why JAX-RS POST does not work with multivalued map

I have JAX-RS 2.8.9 with Spring 4.3.4 app. I perform a very simple POST request to the following server code
#POST
#Consumes({MediaType.APPLICATION_FORM_URLENCODED})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response test(MultivaluedMap<String, String> work) {
return Response.ok(work.keySet().size()).build();
}
I test with curl:
curl -i -X POST 'http://localhost:XXX/some/test' -d "param=value&param2=value2" -H "Content-Type: application/x-www-form-urlencoded"
I get the following warning
A servlet request to the URI http://localhost:XXX/some/test contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.
About which I found only cause that involve connection issues, apparently I don't have.
According to documentation this is the way to handle a case when we have a variable number of FormParams passed.
This works, though.
#POST
#Consumes({MediaType.APPLICATION_FORM_URLENCODED})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response test(#FormParam("param") String param) {
return Response.ok(param).build();
}
What can be the reason the multivalued map doesn't? Could it be some filtering? What is an alternative for unknown number of parameters?
UPDATE
Is is due to a particularity of Jersey + Spring.
A solution can be found in this answer.
What can be the reason the multivalued map doesn't? Could it be some filtering? What is an alternative for unknown number of parameters?
By default, it seems your JAX-RS implementation is detecting the form-input and reading/processing the body before it gets to your method. Have you tried:
#POST
#Consumes({MediaType.APPLICATION_FORM_URLENCODED})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response test(Form workForm) {
MultivaluedMap<String,String> work = workForm.asMap();
return Response.ok(work.keySet().size()).build();
}
?
Form is a special JAX-RS class that encapsulates all the form parameters and should be usable as an input parameter to your method.

How to access parameters in a RESTful POST method

My POST method looks like this:
#POST
#Consumes({"application/json"})
#Path("create/")
public void create(String param1, String param2){
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
When I create a Jersey Client in Netbeans the method who calls the post method looks like this:
public void create(Object requestEntity){
webResource.path("create").type(MediaType.APPLICATION_JSON).post(requestEntity);
}
When running this test:
#Test
public void hello(){
String json = "{param1=\"hello\",param2=\"hello2\"}";
this.client.create(json);
}
It gives the following output in the server:
INFO: param1 = {param1="hello",param2="hello2"}
INFO: param2 =
What do I need to change so that the parameters are giving the correct value?
Your #POST method should be accepting a JSON object instead of a string. Jersey uses JAXB to support marshaling and unmarshaling JSON objects (see the jersey docs for details). Create a class like:
#XmlRootElement
public class MyJaxBean {
#XmlElement public String param1;
#XmlElement public String param2;
}
Then your #POST method would look like the following:
#POST #Consumes("application/json")
#Path("/create")
public void create(final MyJaxBean input) {
System.out.println("param1 = " + input.param1);
System.out.println("param2 = " + input.param2);
}
This method expects to receive JSON object as the body of the HTTP POST. JAX-RS passes the content body of the HTTP message as an unannotated parameter -- input in this case. The actual message would look something like:
POST /create HTTP/1.1
Content-Type: application/json
Content-Length: 35
Host: www.example.com
{"param1":"hello","param2":"world"}
Using JSON in this way is quite common for obvious reasons. However, if you are generating or consuming it in something other than JavaScript, then you do have to be careful to properly escape the data. In JAX-RS, you would use a MessageBodyReader and MessageBodyWriter to implement this. I believe that Jersey already has implementations for the required types (e.g., Java primitives and JAXB wrapped classes) as well as for JSON. JAX-RS supports a number of other methods for passing data. These don't require the creation of a new class since the data is passed using simple argument passing.
HTML <FORM>
The parameters would be annotated using #FormParam:
#POST
#Path("/create")
public void create(#FormParam("param1") String param1,
#FormParam("param2") String param2) {
...
}
The browser will encode the form using "application/x-www-form-urlencoded". The JAX-RS runtime will take care of decoding the body and passing it to the method. Here's what you should see on the wire:
POST /create HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 25
param1=hello&param2=world
The content is URL encoded in this case.
If you do not know the names of the FormParam's you can do the following:
#POST #Consumes("application/x-www-form-urlencoded")
#Path("/create")
public void create(final MultivaluedMap<String, String> formParams) {
...
}
HTTP Headers
You can using the #HeaderParam annotation if you want to pass parameters via HTTP headers:
#POST
#Path("/create")
public void create(#HeaderParam("param1") String param1,
#HeaderParam("param2") String param2) {
...
}
Here's what the HTTP message would look like. Note that this POST does not have a body.
POST /create HTTP/1.1
Content-Length: 0
Host: www.example.com
param1: hello
param2: world
I wouldn't use this method for generalized parameter passing. It is really handy if you need to access the value of a particular HTTP header though.
HTTP Query Parameters
This method is primarily used with HTTP GETs but it is equally applicable to POSTs. It uses the #QueryParam annotation.
#POST
#Path("/create")
public void create(#QueryParam("param1") String param1,
#QueryParam("param2") String param2) {
...
}
Like the previous technique, passing parameters via the query string does not require a message body. Here's the HTTP message:
POST /create?param1=hello&param2=world HTTP/1.1
Content-Length: 0
Host: www.example.com
You do have to be particularly careful to properly encode query parameters on the client side. Using query parameters can be problematic due to URL length restrictions enforced by some proxies as well as problems associated with encoding them.
HTTP Path Parameters
Path parameters are similar to query parameters except that they are embedded in the HTTP resource path. This method seems to be in favor today. There are impacts with respect to HTTP caching since the path is what really defines the HTTP resource. The code looks a little different than the others since the #Path annotation is modified and it uses #PathParam:
#POST
#Path("/create/{param1}/{param2}")
public void create(#PathParam("param1") String param1,
#PathParam("param2") String param2) {
...
}
The message is similar to the query parameter version except that the names of the parameters are not included anywhere in the message.
POST /create/hello/world HTTP/1.1
Content-Length: 0
Host: www.example.com
This method shares the same encoding woes that the query parameter version. Path segments are encoded differently so you do have to be careful there as well.
As you can see, there are pros and cons to each method. The choice is usually decided by your clients. If you are serving FORM-based HTML pages, then use #FormParam. If your clients are JavaScript+HTML5-based, then you will probably want to use JAXB-based serialization and JSON objects. The MessageBodyReader/Writer implementations should take care of the necessary escaping for you so that is one fewer thing that can go wrong. If your client is Java based but does not have a good XML processor (e.g., Android), then I would probably use FORM encoding since a content body is easier to generate and encode properly than URLs are. Hopefully this mini-wiki entry sheds some light on the various methods that JAX-RS supports.
Note: in the interest of full disclosure, I haven't actually used this feature of Jersey yet. We were tinkering with it since we have a number of JAXB+JAX-RS applications deployed and are moving into the mobile client space. JSON is a much better fit that XML on HTML5 or jQuery-based solutions.

Categories

Resources