I wanted to fetch the List of Entities from database at Front end.
So I have written POST REST HTTP call in Spring MVC.
But I read the HTTP documentation which says whenever you have to retrieve data from database prefer GET call.
So, Is it there is any I can replace the POST call to GET call from angular JS and pass list of Integers.
But, GET HTTP has many drawbacks like : the length of URL is limited.Considering the case where we have to fetch 1000 entities from database.
Please suggest me the possible way to get the entities or write GET REST API in Spring MVC for list of integers(refers to ID's of Entities).
For Example : Consider there are 100 books in book table, But I want only few books, say id : 5,65,42,10,53,87,34,23.
Thats why I am passing this List of Id's in a List of Integer in POST call.
Currently stuck how to convert this to GET call. In Short, how to pass List of Integers through GET REST call.
I prefer a variant through HTTP path variable for your problem, because of in REST ideology a resource ID is passed after a resource name 'http://../resource/id' and HTTP parameters are used for filtering.
Through HTTP parameters
If you need to pass your ids through HTTP parameters, see an axample below:
Here is your Spring MVC controller method:
#RequestMapping(value = "/books", params = "ids", method = RequestMethod.GET)
#ResponseBody
Object getBooksById_params(#RequestParam List<Integer> ids) {
return "ids=" + ids.toString();
}
And you can make a call using next variants:
http://server:port/ctx/books?ids=5,65,42
http://server:port/ctx/books?ids=5&ids=65&ids=42
Also take a look this discussion: https://stackoverflow.com/a/9547490/1881761
Through HTTP path variables
Also you can pass your ids through path variable, see an example below:
#RequestMapping(value = "/books/{ids}", method = RequestMethod.GET)
#ResponseBody
Object getBooksById_pathVariable(#PathVariable List<Integer> ids) {
return "ids=" + ids.toString();
}
And your call will be look like this: http://server:port/ctx/books/5,65,42
Pros of GET HTTP call : It is always used for retrieval of Data.(From this perspective : we should implemented for each and every and retrieval)
Through HTTP parameters
If you need to pass your ids through HTTP parameters, see an axample below:
Here is your Spring MVC controller method:
#RequestMapping(value = "/book", params = "ids", method = RequestMethod.GET)
#ResponseBody
Object getBooksById_params(#RequestParam List<Integer> ids) {
return "ids=" + ids.toString();
}
It works fine but for exceptional case : say URI is above 2048 characters. It means there are many Id's in the list(eg : 1000)
then its throws an exception :
return 414 (Request-URI Too Long)
which is http://www.checkupdown.com/status/E414.html
After some research MY UNDERSTANDING is : The HTTP protocol does not place any a priori limit on the lenght of a URI. Servers MUST be able to handle the URI of any resources they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414(Request_URI Too Long) status if a URI is longer than the server can handle.
I have also gone through sites like to get the GET URI length :
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.1
So conclusion, is stick to POST call when there can be variable URI length at runtime for not getting such exception[return 414 (Request-URI Too Long)]
Alternatively, to allow for complex queries you'll need to give the query its own rest language. So to create a query you POST to /library/query then you edit it with things like POST /library/query/12345 with data {id:34} and then you execute the query with GET /library/books?query=12345
Simply you can call list like this:
***/users?id=1&id=2
If you want to read entities from your API you have to use a GET call.
The better way to get them all is to use a query params as filter.
REST DESIGN cannot retrieve more than one entity each time by id.
An example:
GET /library/books/58731 -> returns only one book identified by 58731
GET /library/books?numPages>70 returns all the books with more than 70 pages
I think that If you need to retrieve a lot of books because they have some logic that all matches, try to put it as a queryString.
Another example:
GET /library/books?stored>20150101 returns all the books added to library on 2015
If you give us more information about the collection and the requirements we will answer more directly.
Related
I want to have the same Endpoint for three different operations in one Request Method type as GET in REST Controller in Spring MVC application.
For example three operations GET Request Method:1 . ListofItems, 2. LoadDropdown,3. searchoneParticularItem.
Endpoint 1:/items this end point I could use it to list the items
Endpoint 2:/items/{itemId} this endpoint I could use it to search particular object.
How can I get the third operation load the drop downs of items?
Please give me some example to have atleast three operations in GET with same Endpoint.
It takes String[] in value, it can handle multiple urls, use
#RequestParam(value=["mapping1","mapping2","mappping3"]);
#RequestMapping value attribute takes String[], so you can map multiple URLs to the same controller method as shown below:
#RequestMapping(value={"/listItems", "/dropdownItems",
"/items/{itemId}"}, method=RequestMethod.GET)
public String loadItems(#PathVariable String item, Model model) {
//add items to model
//return JSP or HTML
}
You can refer here
I'm looking for the hash equivalent of this question: How to pass array query params to AWS API Gateway?
Basically, I want to set up query parameters that look like this:
example.com?color[background]=yellow&color[foreground]=black
When I try to create a query parameter called color[background] in the API Gateway console, I get the following error message:
Invalid mapping expression specified: Validation Result: warnings : [], errors : [Parameter name should be a non-empty alphanumeric string]
I've also tried setting up a color query param and then passing various "hashes" to it. Here's what I've tried passing into this parameter:
{"background" => 123, "foreground" => "abc"} and removing the spaces
{"background" : 123, "foreground" : "abc"} and removing the spaces
{background:123,foreground:abc}
They all result in a request that is some form of example.com?color=%7Bbackground:123,foreground:abc%7D with the hash that I pass coming after the =.
Any ideas? Is this bad practice for query string parameters anyways, and should I stick with simple params?
Since there isn't a standard defined to pass in complex data structures like arrays or maps via the query string, API Gateway does not attempt to to interpret or parse the query string as anything other than simple key-value string pairs.
If you want to pass in and transform complex types it's best to do so in the body of a POST or PUT request where you can leverage JSON and API Gateway's powerful body mapping templates feature.
Alternatively, if you must stick with query string parameters, then you must either:
Collapse your data structure to be simple key value pairs as suggested by Michael -sqlbot above, or
Passthrough the raw query string to your backend lambda or http integration where it can parsed as you please. See this post for more details on how to do that.
From the API docs dynamo db does support pagination for scan and query operations. The catch here is to set the ExclusiveStartIndex of current request to the value of the LastEvaluatedIndex of previous request to get next set (logical page) of results.
I'm trying to implement the same but I'm using DynamoDBMapper, which seems to have lot more advantages like tight coupling with data models. So if I wanted to do the above, I'm assuming I would do something like below:
// Mapping of hashkey of the last item in previous query operation
Map<String, AttributeValue> lastHashKey = ..
DynamoDBQueryExpression expression = new DynamoDBQueryExpression();
...
expression.setExclusiveStartKey();
List<Table> nextPageResults = mapper.query(Table.class, expression);
I hope my above understanding is correct on paginating using DynamoDBMapper.
Secondly, how would I know that I've reached the end of results. From the docs if I use the following api:
QueryResult result = dynamoDBClient.query((QueryRequest) request);
boolean isEndOfResults = StringUtils.isEmpty(result.getLastEvaluatedKey());
Coming back to using DynamoDBMapper, how can I know if I've reached end of results in this case.
You have a couple different options with the DynamoDBMapper, depending on which way you want go.
query - returns a PaginatedQueryList
queryPage - returns a QueryResultPage
scan - returns a PaginatedScanList
scanPage - returns a ScanResultPage
The part here is understanding the difference between the methods, and what functionality their returned objects encapsulate.
I'll go over PaginatedScanList and ScanResultPage, but these methods/objects basically mirror each other.
The PaginatedScanList says the following, emphasis mine:
Implementation of the List interface that represents the results from a scan in AWS DynamoDB. Paginated results are loaded on demand when the user executes an operation that requires them. Some operations, such as size(), must fetch the entire list, but results are lazily fetched page by page when possible.
This says that results are loaded as you iterate through the list. When you get through the first page, the second page is automatically fetched with out you having to explicitly make another request. Lazy loading the results is the default method, but it can be overridden if you call the overloaded methods and supply a DynamoDBMapperConfig with a different DynamoDBMapperConfig.PaginationLoadingStrategy.
This is different from the ScanResultPage. You are given a page of results, and it is up to you to deal with the pagination yourself.
Here is quick code sample showing an example usage of both methods that I ran with a table of 5 items using DynamoDBLocal:
final DynamoDBMapper mapper = new DynamoDBMapper(client);
// Using 'PaginatedScanList'
final DynamoDBScanExpression paginatedScanListExpression = new DynamoDBScanExpression()
.withLimit(limit);
final PaginatedScanList<MyClass> paginatedList = mapper.scan(MyClass.class, paginatedScanListExpression);
paginatedList.forEach(System.out::println);
System.out.println();
// using 'ScanResultPage'
final DynamoDBScanExpression scanPageExpression = new DynamoDBScanExpression()
.withLimit(limit);
do {
ScanResultPage<MyClass> scanPage = mapper.scanPage(MyClass.class, scanPageExpression);
scanPage.getResults().forEach(System.out::println);
System.out.println("LastEvaluatedKey=" + scanPage.getLastEvaluatedKey());
scanPageExpression.setExclusiveStartKey(scanPage.getLastEvaluatedKey());
} while (scanPageExpression.getExclusiveStartKey() != null);
And the output:
MyClass{hash=2}
MyClass{hash=1}
MyClass{hash=3}
MyClass{hash=0}
MyClass{hash=4}
MyClass{hash=2}
MyClass{hash=1}
LastEvaluatedKey={hash={N: 1,}}
MyClass{hash=3}
MyClass{hash=0}
LastEvaluatedKey={hash={N: 0,}}
MyClass{hash=4}
LastEvaluatedKey=null
I am trying to write a REST service with Jersey where the GET method should write me a list of objects. The input to the GET method should take the ids of the list.
Say I will pass n numbers of EmployeeId and the service should return me a list of employees.
If it is not possible to have #Consumes in the GET method, will there be any problem in using other methods of http like PUT or POST to retrieve the list of objects?
Using POST and PUT for resource retrieval contradicts the conventions established for the usage of REST over HTTP. Switching to either of them just for the sake of using a #Consumes annotation is simply wrong.
If you need to provide additional scoping information for a collection of resources, place it in the URL. Specifically, you can use query parameters. It's a common pattern to implement pagination this way (by providing some limit and offset parameters). Your use case is very similar.
Let's assume this is the URL of a collection of employee resources
GET http://www.example.com/employees
A single employee could be fetched like this:
GET http://www.example.com/employees/id1
If you want to retrieve several employees, you could use a query string like this:
GET http://www.example.com/employees?ids=id1;id3;id8
The identifiers do not need to be delimited by semicolons, this is just an example of a way you could fetch them. Remember that it's treated as a single parameter! You'll have to split the values.
Here's how you could read such a list from the URL above
#Path("employees")
#GET
public Response getEmployees(#QueryParam("ids") String employees){
List<String> ids = Arrays.asList(employes.split(";"));
// Validate the ids, get data from a database,
// prepare a response and return it
}
Parsing the list can be cumbersome, especially if you want to validate the ids somehow. Jersey has a neat feature you can use here. If a class has a single-string-parameter constructor or a SomeType parse(String) method, it can be injected by the framework by parsing the string passed as a parameter (QueryParam, PathParam, FormParam, etc.)
You can take advantage of it to make your resource class cleaner.
#Path("employees")
#GET
public Response getEmployees(#QueryParam("ids") Employees e){
doFancyStaffWithAValidListOfEmployees(e.asList());
//prepare a response
}
Where Employees is a class with a String constructor or a parse method, containing all the splitting and validation logic, possibly even some database queries.
Here's a nice article on writing such parameter classes
I currently have a .NET method that looks like this - GetUsers(Filter filter) and this is invoked from the client by sending a SOAP request. As you can probably guess, it takes a bunch of filters and returns a list of users that match those filters. The filters aren't too complicated, they're basically just a set of from date, to date, age, sex etc. and the set of filters I have at any point is static.
I was wondering what the RESTful way of doing this was. I'm guessing I'll have a Users resource. Will it be something like GET /Users?fromDate=11-1-2011&toDate=11-2-2011&age=&sex=M ? Is there a way to pass it a Filter without having to convert it into individual attributes?
I'm consuming this service from a mobile client, so I think the overhead of an extra request that actually creates a filter: POST filters is bad UX. Even if we do this, what does POST filters even mean? Is that supposed to create a filter record in the database? How would the server keep track of the filter that was just created if my sequence of requests is as follows?
POST /filters -- returns a filter
{
"from-date" : "11-1-2011",
"to-date" : "11-2-2011",
"age" : "",
"sex" : "M"
}
GET /Users?filter=filter_id
Apologies if the request came off as being a little confused. I am.
Thanks,
Teja
We are doing it just like you had it
GET /Users?fromDate=11-1-2011&toDate=11-2-2011&age=&sex=M
We have 9 querystring values.
I don't see any problem with that
The way I handle it is I do a POST with the body containing the parameters and then I return a redirect to a GET. What the GET URL looks like is completely up to the server. If you want to convert the filter into separate query params you can, or if you want to persist a filter and then add a query param that points to the saved filter that's ok too. The advantage is that you can change your mind at any time and the client doesn't care.
Also, because you are doing a GET you can take advantage of caching which should more than make up for doing the extra retquest.