REST API POST Response after multiple objects are created? - java

I'm creating tasks with various properties and I'm passing the JSON data from Angular frontend to Java based backend. Assignee is a property of the Task class at the moment.
A new request came in to change the behavior: The user should be able to select multiple assignees upon creating a new task.
The way I want to handle this is that I want to create the same amount of tasks as the number of assignees passed. So if n users are passed with the various task data, n tasks would be created in the DB for each user as an assignee.
Previously I could only pass one assignee and the code for returning the POST request's response was the following:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(TaskInDto taskInDto) {
// saving to DB, etc...
String taskId = createdTask.getId().toString();
URI taskUri = uriInfo.getAbsolutePathBuilder().path(taskId).build();
return Response.created(taskUri).build();
}
My question is regarding REST design: What should I return as a Result object to the user if multiple objects were created?

If a POST request is creating multiple objects, clients will expect back a response entity containing links to each created resource.

Related

Java Quarkus streaming endpoint how to handle parameters?

I have a redis cache that gets populated by items asynchronously. I'm trying to get this endpoint to return a stream to that redis cache once an item has appeared.
#GET
#Path("/myRedis/{id}")
#Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<String> stream(#PathParam String id) {
return redisCache.get(id); // this returns a string
}
So say we have two users A and B
A requests item a by calling localhost:8080/myRedis/1 the item does not exist yet but a connection has been created to the streaming endpoint and after say 2 seconds the item appears and A gets it
Meanwhile B also requests an item b by calling localhost:8080/myRedis/2 the item exist directly and B gets it
How can I modifiy the code above to achieve this?

Handle Concurrency in Spring Controller Instance variables

I am using Spring 5 for a web application. Here to check whether my search query based on some inputs from html page is returning Empty value or NOT. If empty then I am showing a no Data found notification.
I have used two methods in controller for this.
After filling the search fields I make an ajax call to the controller on button click. If data is found the controller method returns a flag which i check in the JavaScript code to check data is available or not.
If data is present then I change the attribute of form element like action to another URL and target="_blank" and make a form submit.
I have to generate a jasper report on final submit.
BUT to avoid two query hits on DATABASE , while making the first query hit on database I am storing the value to a INSTANCE VARIABLE in spring controller,
Which I am retrieving on final form submit and generating the report from the data.
I searched for answers but not getting a perfect idea how to apply in my code,
It would be of great on your part to share me with right way to implement.
******JAVA CODE*******
public class HrmsSalarySlipSummaryReportController {
List<Object[]> allowanceDetails;
List<Object[]> deductionDetails;` #PostMapping(value = "/reportIsEmptyCheckSal", headers = "Accept=application/json", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> summaryListIsEmpty(#RequestBody HrmsSalarySlipReportDTO slipReportDTO) {
allowanceDetails = summarySalReportServ.getAllowanceDetails(slipReportServ.getIntParameters(slipReportDTO, userSession.getUlbId()));
deductionDetails = summarySalReportServ.getDeductionDetails(slipReportServ.getIntParameters(slipReportDTO, userSession.getUlbId()));
return ResponseEntity.ok(summarySalReportServ.isJsonEmpty(allowanceDetails, deductionDetails));
}`
How to handle concurrency issue along with checking the empty returned result
Thanks.

Instance Variables with web based project

I'm working with a Spring web project but I'm facing a problem with an instance variable, I use a List to store a report data, when a user request this report I store this List in order to use it later for an Excel generation, but when another user requests the same report the List is re-write with the new data requested and when the first user download the report, it comes with the data that was requested form the second user.
My class:
public class foo{
List<Service> services;
GetMapping({"/Report/Detail"})
String getReport(Parameters params, ModelMap model){
services = new ArrayList<>();
//A lot of stuff
services = serviceRepository(params);
//A lot of stuff
model.addAttribute("services",services)
return "ReportDetail";
}
GetMapping({"/Report/Detail/Excel"})
byte[] getExcelReport(){
//Using the List<services> here to download the report
//this List is getting modified by the second user
byte[] excelReport = excelService(services);
return excelReport;
}
}
I don't want to do major changes because the class is too large, it works perfect but I have this problem and I'm looking for a workaround.
Any advice will apreciate.
Best!
Every time a user sends a request to /Report/Detail you overwrite the services list. If you want each user to have their own list then you have to use a different approach. For example you could use a Map that stores users (key should uniquely identify the user) and their respective lists.
Map<UserKey, List<Service>> services;
And later in the method get the correct list by
List<Service> userServices = services.get(userKey);
In case of distributed application, you would of course have to use a distributed map (possibilities include for example Hazelcast or Ehcache)

How to redirect from SpringFormController based on input parameters?

Here's the basic requirement:
An http request is received by page A that may have parameters defined.
If parameters are defined, page A processes the request and automatically forwards to page B. If parameters are not defined, display page A with a form for the user to fill in and submit. On submit, process the request and forward to page B.
Basically, I want to bypass the need for the user to enter data via onSubmit() if the data has already been provided as input parameters to page A. How can I do this?
Page A and B are implemented by extending the (deprecated) SimpleFormController. One way I've done this before is to place a "hidden" page (A′) that accepts the request and, if parameters are defined, processes the data and redirects to B. If the parameters are not provided, then I redirect to A where the processing is done.
This doesn't seem efficient to me, as it duplicates a lot of the processing code.
I'm not providing any code, since it doesn't easily explicate the question.
I hope I understand but you want a method in controller that will direct based on information provided.
Here is something i knocked up quickly that i hope will help solve the problem:
#RequestMapping("/pageA/{parameter}")
public String displayPageA(Model model, #PathVariable String parameter) {
if(parameter == null)
{
model.addAttribute("your_form", new YourForm());
return "pageA";
}
else {
return "redirect:/pageB/"+parameter; // this is if you want the parameter passed on
}
}

spring mvc ajax form post handling, possible methods and their pros and cons [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I'm currently learning using Spring MVC. During development, I used four different kind of form handling with Ajax & jQuery. Now, I'm wondering what are advantages and disadventages of each methods. Are there any others?
Let's say we have a really simple form with just 2 inputs
<input id="name" type="text" value"Name">
<input id="active" type="checkbox">
<input type="button" onclick="submitForm()">
Let's assume that we are not validating data either on client and server site. We will also omitt handling data returned. I'm just interested in sending data to server.
Now how can we handle submit? My solutions were:
1. Request based on PathVariable
JS sending request would look sth like this:
function submitForm() {
var name = jQuery("#name").val();
var active = jQuery("#active").is("checked");
jQuery.ajax("/Submit/Name/" + name + "/Active/"+ active + "/",
{
type:"POST"
});
}
And also Controller:
#RequestMapping(value="/Submit/Name/{name}/Active/{active}/",method=RequestMethod.POST)
publis void submitForm(#PathVariable String name, #PathVariable Boolean active)
{ //something not important here }
Pros in my opinion
quick way to recieve data in Controller, simple annotation make it works
type maching for basic types of data (String, Boolean, Numeric)
Cons
request address grows with data needed
problem with special characters in url? Not sure about this one, but I remember my teammate had problem with / used as char in data sended to server
2. Request with data
I haven't got clue how name it, but this is the idea in JS file:
function submitForm() {
var name = jQuery("#name").val();
var active = jQuery("#active").is("checked");
var object = {name:name,active:active};
jQuery.ajax("/Submit/",
{
type:"POST",
data: object
});
}
And Controller:
#RequestMapping(value="/Submit/",method=RequestMethod.POST)
publis void submitForm(#RequestParam(value="name") String name, #RequestParam(value="active") Boolean active)
{ //something not important here }
In my opinion, not much different from first method, but:
Pros
shorter request address
Cons
method declaration with many parameters may be huge
3.Sending JSON to server as PathVariable
In JS file:
function submitForm() {
var name = jQuery("#name").val();
var active = jQuery("#active").is("checked");
var object = {name:name,active:active};
jQuery.ajax("/Submit/" + JSON.stringify(object),
{
type:"POST"
});
}
And Controller
#RequestMapping(value="/Submit/{json}",method=RequestMethod.POST)
publis void submitForm(#RequestParam(value="name") String name, #RequestParam(value="active") Boolean active)
{
//now we are actually doing sth important here, cause we need to parse JSON
}
Pros
short request address
short method declaration
Cons
JSON parsing on my own
4.JSON as RequestBody with class mapped
My favourite method, but not always possible as we need to write multiple class just for wrapping sent data, JS:
function submitForm() {
var name = jQuery("#name").val();
var active = jQuery("#active").is("checked");
var object = {name:name,active:active};
jQuery.ajax("/Submit/",
{
type:"POST",
data:JSON.stringify(object)
});
And Java code:
public class Wrapper {
private String name;
private Boolean active;
//getters and setters
}
#RequestMapping(value="/Submit/",method=RequestMethod.POST)
publis void submitForm(#RequestBody Wrapper wrapper)
{
//all data available with Wrapper class
}
Pros
mapping into desired object
quick and simple
Cons
we need to write wrappers for every data sent to server
That would be all I know currently. I would appreciate and critism, suggestions for better solutions or anything. Thanks!
(1) Request based on PathVariable
As you said you will get problems with special characters (such as /). Path-based URLs are most readable if left short. E.g., /hotel/{h}/room/{r}. Sometimes, a combination of path and request parameters are used to denote mandatory vs optional parameters.
(2) Request with data
This would be a great approach giving you flexibility to easily add/remove Request Parameters as well as managing different combinations of parameters.
(3) Sending JSON to server as PathVariable
I see the same technical problems with this approach as (1). Without proper escaping (and Spring at the current time of writing can't handle / in any form) this option is not viable. (4) is the way to do this.
(4) JSON as RequestBody with class mapped
This would be preferable for complex objects. Typically spring can help you map json to Java objects directly. The tradeoff is that it cannot be tested as easily from a browser. I believe this is a common pattern in RESTful services, although it doesn't necessarily dictate a transmission technology.
In summary,
using query parameters is simple, and enables users to test the service directly from the browsers address bar.
using objects in the request body is useful to get flexibility in handling complex data but cannot as easily be tested from the browser.
The path-variable options don't fair well with spring unless well-formed data withouth special characters such as / are submitted.
I do very often the (2) and the (4) methods.
The (2) because of its flexibility.
The (4) when I need high coupled datas and want to validate input easily i.e. with #Valid annotation added to the Controller's method parameter I use to bind the datas sent.
I mostly do 1, 2, and 4.
Spring Roo will and does autogenerate code for 1, 2 and 4.
1, 2, and 4 largely depend on whether or not your doing a POST, GET, PUT, DELETE (CRUD respectively).
Number 1 - Path Variable
Is almost always GET for a single item. It is the READ in CRUD.
Number 2 - Request Parameter
For true REST this should be for optional parameters like paging a list or filters for search using GET. There should be no request body.
For POST its also used for old school REST and most importantly for traditional HTML FORMS (aka application/x-www-form-urlencoded.
This is important because its much easier for people do this one (#2) for POST than #4.
Number 3 - Don't do this.
Others have stated why.
Number 4 - JSON Request Body
This is almost always done for a POST and PUT (aka C and U of the CRUD). Its usually combined with a PathVariable to specify which item(s).
This is hard to test in a browser and requires your clients know the valid format to make updates. ie. Name Value pairs are easier to doc and understand then JSON/XML schema.
What I do
Lately I have been doing number #2 so that I can support both HTML full loads or data only loads of JSON for Single Page Applications.
I do it through a custom view resolver so that I don't have to write two methods for every request.
Otherwise you'll have to make two methods for each request (one with application/json and the other one for HTML).
#RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public Object doJson() {}
#RequestMapping(method = RequestMethod.POST)
public Object doHtml() { //after processing redirect. }

Categories