Passing MultipartFormDataInput between services - quarkus

I am working on a project where I need to upload some files and for that I am using MultipartFormDataInput as container for the files.
The bird-eye view of this construct is as follow
Frontend -> Gateway -> Service Module
The Service module contains more than one functionality and one of them is the upload
I first implemented the upload of files in "Service module" and successfully tested it with Postman.
The signature of the method is as follow
#POST
#Path("{id}/files")
#Consumes(MULTIPART_FORM_DATA)
public Response saveFiles(#PathParam("id") String id, #MultipartForm MultipartFormDataInput input)
I then moved to the "Gateway" Service and implemented the part that should receive the code from the Frontend and the signature is as follow
#POST
#Path("{id}/files")
#Consumes(MULTIPART_FORM_DATA)
public Response saveFiles(#PathParam("id") String id, #MultipartForm MultipartFormDataInput input)
which is the same signature as the one in the "Service" module.
I tested it with PostMan and the Gateway correctly receives the files and the MultipartFormDataInput but passing it with the RestClient which code is following, the Service module now receives an empty MultipartForm.
Am I missing something or do I need to do things differently in order to pass the MultipartForm as I will surely have the same problem when trying to implement the code in the Frontend module.
#RegisterRestClient
#RegisterClientHeaders
#ClientHeaderParam(name = APPLICATION_NAME, value = "gateway")
#Path("/voters")
#RequestScoped
public interface VotersClient {
#POST
#Path("{id}/files")
#Consumes(MULTIPART_FORM_DATA)
Response saveFiles(#PathParam("id") String id, #MultipartForm MultipartFormDataInput input);
}

Related

Quarkus RestClient get response from redirect

I'm using Quarkus Rest Client to perform a GET request to an external API service. This service, however, does not directly return the resource (XML) I need to receive, but it performs a redirect to another API service which returns the resource.
When I try to navigate to the path which asks the API service for the resource (i.e. localhost:8080/hello) I get redirected to the page with the resource instead of receiving and processing it.
Putting a breakpoint after the request, shows that the part of the code after the request is never reached.
Here is the code of the endpoint:
#Path("/hello")
public class GreetingResource {
#Inject
#RestClient
MyService myService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
myService.performGet();
return "you are here"; // breakpoint here, it is never reached
}
}
And here is the code of MyService:
#Path("/..")
#RegisterRestClient(configKey="key")
public interface MyService {
#GET
#Path("/..")
#Produces(MediaType.TEXT_XML)
String performGet(#QueryParam("c") String c, #QueryParam("d") String d);
}
I have tried to add the configuration key/mp-rest/followRedirects=true, but I still get the same problem. Also, with a path without redirects, everything works fine.
Using the native HttpURLConnection also works fine, but, since I am using Quarkus, I would like to use its features instead.

Spring Boot REST controller not returning HTML string

I have a Spring Boot app that has one controller that serves mostly RESTful endpoints, but it has 1 endpoint that actually needs to return HTML.
#RestController
#RequestMapping("v1/data/accounts")
public class AccountResource {
// Half a dozen endpoints that are all pure data, RESTful APIs
#GetMapping("/confirmRegistration")
public void confirmRegistration(#RequestParam(value = "vt") String token) {
// Some logic goes here
System.out.println("This should work!");
return ResponseEntity.ok('<HTML><body>Hey you did a good job!.</body></HTML>')
}
}
When this runs, no errors/exceptions get thrown at all, and in fact I see the "This should work!" log message in my app logs. However from both a browser and a curl command, the HTTP response is empty. Any idea what I need to change in the ResponEntity builder to get the server returning a hand-crafted HTML string?
Add this to your #RequestMapping or #GetMapping
produces = MediaType.TEXT_HTML_VALUE
Spring defaults to application\json. If you need any other type, you need to specify it.

Uploading files using the Spring Framework and jquery-upload-file plugin issue

I am having trouble uploading files via AJAX from my web-client to my Server. I am using the following jQuery library in the client-side to do the file upload: https://github.com/hayageek/jquery-upload-file
In the server-side, I'm using Spring Framework and I have followed the following Spring Tutorial to build my Service: https://spring.io/guides/gs/uploading-files/
At first, my server method looked like this (file was defined as #RequestParam):
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestParam("file") MultipartFile file){
//functionality here
}
but every time I submitted the Upload form I got a Bad Request message from the Server, and my handleFileUpload() method was never called.
After that, I realized the file was not being sent as a Request Parameter so I defined file as #RequestBody, and now my method looks like this:
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestBody("file") MultipartFile file){
//functionality here
}
Now handleFileUpload() is called every time the Upload form is submitted, but I am getting a NullPointerException every time I want to manipulate file.
I want to avoid submitting the form by default, I just want to do it through AJAX straight to the Server. Does anybody know what could be happening here?
you may try changing the signature of the method to
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(MultipartHttpServletRequest request){
Iterator<String> iterator = request.getFileNames();
while (iterator.hasNext()) {
String fileName = iterator.next();
MultipartFile multipartFile = request.getFile(fileName);
byte[] file = multipartFile.getBytes();
...
}
...
}
this works with jQuery File Upload in our webapp. If for some reason this does
not work for you, you may try to isolate the problem, by inspecting the HTTP
request issued by the jQuery File Upload (for example, with Fiddler), and debugging the response starting from Spring
DispatcherServlet.

Parsing JSON request body with Spring MVC

I am using Spring 4.1 framework for developing webservices. When I return a Java object as response, it is automatically converted to JSON and delivered to client, so I assume that JSON parser is in classpath and it is configured properly. However it fails to convert the request body from JSON into Java object and client is getting a HTTP response of 400.
Here is how the webservice looks like:
public class Details{
public Details(){
}
int code;
int area;
}
#RequestMapping(value = "/api/update/{phoneNumber}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> update(#PathVariable final String phoneNumber, #RequestBody Details details)
Here is how the request looks like:
Method: Post
Content-Type: application/json; charset=utf-8
Body: {"code":0,"area":12}
If I collect the request body as string and parse it manually then it works, so it gets the valid JSON but for some reason it is not parsing it automatically. I have no clue on how to fix it. Please help. Thanks in advance.
You have package-private properties in your Details class, so they are probably not recognised by json-converter.
You have several options:
define them as public (not recommended)
provide getters and setters
if you are using jackson, you can annotate them with #JsonProperty, leaving them package-private
Finally I got the reason for this. I was using inner classes which were not static. Making those static fixed the issue.

Global param on multiple webresources

I am building a webservices application using jersey,jax-rs
I have single jax-rs resource file at path "/authenticate"
I have multiple methods with individual paths like "/user" "/test"
#Path ("/authenticate")
public class Authenticate{
private static final Log log = LogFactory.getLog(Authenticate.class);
#QueryParam("entityId")
String entity;
#GET
#Path ("/{param}")
public Response getMsg(#PathParam ("param") String msg) {
String o = "Hello Welcome Back:"+msg;
return Response.status(200).entity(o).build();
}
#GET
#Path ("/user")
#Produces({"application/json"})
public UserDTO getUser (#Context HttpServletRequest request,
#QueryParam("userId") int userId) {
System.out.println("In Get User, User:"+userId);
System.out.println("In Get User, Entity:"+entity);
}
#GET
#Path ("/test")
#Produces({"application/json"})
public TestPOJO getTestPOJO () {
System.out.println("In Get TestPOJO");
System.out.println("In Get Test, Entity:"+entity);
return new TestPOJO();
}
}
As suggested for jersey client, I am using a single webresource from client and build subsequent webresources from the same webresource by using .path("/xxx").
Here is how I create the initial web resource
WebResource webResource = client.resource("http://localhost:8080/Service/jaxrs/authenticate");
webResource.queryParam("entityId", securityHelper.getEntityId().toString());
Here is how I use the webresource subsequently
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
ClientResponse userRes = webResource.path("/user").queryParams(params).accept("application/json").get(ClientResponse.class);
I want to assign a queryparam to the initial webresource, and I want that to be retained by all subsequent webresources created using the .path(). But that is not happening right now. For example in the above code "entityId" is not available when the call with path("/user") is made.
My idea is to assign common parameters once and all subsequent users of the webResource need not add those again and again. Is there a way to do it? Will this approach work?
The line below creates a new WebResource and not changing the state of the webResource object:
webResource.queryParam("entityId", securityHelper.getEntityId().toString())
Eventually you could change your code like this to create the "base" resource:
WebResource webResource = client.resource("http://localhost:8080/Service/jaxrs/authenticate").queryParam("entityId", securityHelper.getEntityId().toString());
And then use this resource to create another resources as you like. WebResource.queryParam and WebResource.queryParams always create a new WebResource object.
I'm may not be the best person to answer this since I have entered the "world" of Jersey and RESTful servers not too long ago but since i saw this unanswered for 2 days ill try to help out as best as I can.
If i understood correctly you are trying to, by using a query, save the user information on entityId String so it will be available when you make a subsequent call.
Ok let's start with what you have. With your code (entityId as a global parameter), what you are specifying , is that when you are calling a resource from the Authenticate class, any call can be made with a query of the type '?entityId="something" and ANY method in this class can use the information sent in the query.
The thing is, for what I've learned by messing about with Jersey, whenever you make a call, the resource class (in your case Authenticate) is instantiated again. Therefor you can't just keep information in a global parameter since subsequent calls will have the String entityId as null.
This means that if you want to save the information you'll have to do it in a external resource (ex: db, file, etc). What method you choose depends on what you want to do and what are you looking for in your application.
I hope I was at least able to shed a sliver of light on your problem.

Resources