Maybe it's a newbie question so sorry in adavnce :)
I'm having a REST API that returns JSON objects. I'm trying to build a web-site with 2 page:
First page presents a table that presents article titles (let's say we have 'article id', 'author name', 'title'). The 'article id' column is clickable
Second page presents a single article.
I want to be able to click on the id column from the first page, perform a GET request to get the JSON object for the article and then present it nicely in the single-article page. I want the url after the GET request to be something like: `http://[web-server-name]/article/[id]
If I'm writing a static page the uses jQuery to fetch the JSON object then the url will not be in the resources format I'm looking. If I'll return HTML from the REST server it will be ugly both to maintain such page and to couple the logic with the presentation.
What would be the correct way of doing it?
Thanks!
You can have to methods declared at the same #Path but that #Produces two different mime types, the good one is selected accordingly to the Accept header sent by the client:
#GET
#Path("/article/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getArticle(#PathParam("id") long id) {
Article myArticle = getArticleById(id);
return Response.ok(myArticle);
}
#GET
#Path("/article/{id}")
#Produces(MediaType.TEXT_HTML)
public Response getArticleHtml(#PathParam("id") long id) {
InputStream myHtml = getClass().getClassLoader().getResourceAsStream("/path/to/html.html");
return Response.ok(myHtml).build();
}
But that let your Jax-RS implementation serve static resources for which it is not designed to.
Or you can use a Single Page Javascript framework like AngularJS
Related
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.
I am developing an API REST but I faced the following problem: in some cases, the ID of my resources are URLs.
The API is used for both, a software where the IDs are in UUID format, and a FileSystem where the only way of identifying resources is by using their path.
So, to retrieve a resource, I use a GET statement like that:
- http://localhost/files/{id}
When I am retrieving a document stored in the database of the software, {id} is something like "2ab89005-b938-46c8-9d22-3a12a3c40672", but when the document is in a FileSystem, the {id} can be something like "/documents/2018/april/myfile.pdf".
How can I manage this situation? Until now, I am doing a GET request over the URL "http://localhost/files/" (without {id}) and including the required information in the body in JSON format:
{
"id": {id}
}
Of course, I know this is not a good practice, but I don't know how can I implement REST architecture in this situation.
I am using Java + Spring Boot.
Thank you.
SOLUTION IMPLEMENTED:
At the end, I have created the following endpoint: http://localhost/files/?id={id}.
The reson of doing this is because the application that is calling me doesn't know if it is asking for a resource stored in a FileSystem or in my database.
If the application knows it, I think it is better to implement two endpoints: http://localhost/files/?id={id} (for FileSystem) and http://localhost/files/{id} (for database).
It's realy bad idea to take ability for user chose file in FS because of Path Manipulation Vulnerability.
But if you want to do that, you cat set String as a path variable, and decode your request string:
#RestController
#RequestMapping("test")
public class MainController {
#GetMapping("/{id}")
public Mono<String> main(#PathVariable("id") String id){
return Mono.just(id);
}
}
Edit: I no longer have this issue, after a redesign. Should I close this question or something?
My web portal uses backbone to construct the GUI in the browser, and Java Spring MVC on the server to serve and receive data.
In one instance, we show a list of people in the browser, that can be edited. The list is sent from the server like this in JSON:
[{id: 1, title: 'Städare', details: {name: 'Stefan', phone: '123456'}},
{id: 2, title: 'Sotare', details: {name: 'Arne', phone: '234567'}}]
The "details" section for each user contains data that can be edited, "id" is needed by backbone, and "title" is a localized field that is used for presentation only.
My issue is that I want to make a controller method like this for when the user saves changes in this data:
#RequestMappin(value = "/userlist/user/{id}", method = PUT)
public void saveUser(#Valid #RequestBody UserDetails details, #PathVariable("id") String id) {
(...)
}
Here I want details to correspond to the "details" section in the JSON models listed above. But this doesn't work, since when I do model.save() in backbone on a model taken from the list above, it will send the big structure containing "title" and "details", which doesn't map to the UserDetails class that looks like this:
public class UserDetails {
private String name;
private String phone;
(...)
}
My question is: is there a way to either have my Spring MVC controller method receive the "details" part of the request body in an argument (I want it as an argument because I use the #Valid notation to run validations on the data before entering the method), or have backbone only send the details part of the model to the server. While not doing something that feels like to much of a hack.
The obvious alternative is to write a wrapper class that mimics the suberstructure around "details", and use that in the PUT controller. I would prefer not to do this partly because it's a bunch of unnecessary code, and partly because we have had problems with running validators for nested classes.
On the backbone side it should be straight forward and easy to just send the user details section of the json. The documentation also says that you can also just send the part of model that you wish to change on the server.
Docs: http://backbonejs.org/#Model-save
So you can just send the user details for save like below:
model.save(
{name: 'Stefan', phone: '123456'},
{
success:function(model, response, options){},
error:function(model, response, options){}
}
);
The save call in this case will attach the idAttribute to the url and send the attributes hash which in your case is user details.
Dojo grids implement sorting by by issuing requests to REST webservices like so:
GET http://server/request?sort(+id)
Where sort(+id) is the direction (+/-) and the column to sort on.
Currently I'm doing this, and it works, but its ugly:
#GET
#Path("request/")
#Produces(MediaType.APPLICATION_JSON)
public Collection<RequestDataWithCurrentStatus> getAllRequests() {
Collection<RequestDataWithCurrentStatus> col = new ArrayList<RequestDataWithCurrentStatus>();
....
//handle the various types of sorting that can be requested by the dojo widget
String queryString = this.request.getQueryString();
//parse the dojo sort string 'sort(+id)' and sort
...
return col;
}
This method uses a RESTEasy injected #Context private HttpServletRequest request to get access to the raw query string.
I feel like I should be able to map this query string to one of RESTEasy's #*Param annotations in my getAllRequests() invocation. But according to the documentation for RESTEasy, there doesn't seem to be a good mapping to the screwy dojo query string from the doc. I want to do something like this:
#GET
#Path("request/")
#Produces(MediaType.APPLICATION_JSON)
public Collection<RequestDataWithCurrentStatus> getAllRequests( #DojoQueryParam String sort) {
...
}
How do I marshal dojo grid query strings to RESTEasy webservice methods the right way?
I have scarce experience with the old stores / dojox grids, but in case you are using dojo/store/JsonRest: You can change the way it sends the sort param with sortParam. Shamelessly snagged from the reference guide:
var store = new JsonRest({
target: "/FooObject/",
sortParam: "sortBy"
});
This should make requests on the form /foo/bar?sortBy=+id.
http://dojotoolkit.org/reference-guide/1.8/dojo/store/JsonRest.html#sorting
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. }