I am new to java. Trying to develop a application to schedule http api calls in a cron job. Only the method name will be the input. All the apis are configured with swagger annotations. Can I use these annotations to determine whether the api is post or get or delete etc. For example
public class ABC {
#ApiOperation(
httpMethod = "GET",
value = "value",
notes = "notes",
response = ABC.class)
ABC getValue()
{
}
}
only getValue is the input to my application. Can I get the #ApiOperation values to determine the http method type.
You can, but it is in the RequestMapping annotation (the one where you specify which URL should be linked to the method):
For example, this method will be called when someone navigates to myBaseURl/persons in GET. It will return JSON.
#ApiOperation( value = "List of persons",
notes = "List all my base's persons. ",
response = Person.class,
responseContainer = "List",
tags = { "Persons", })
#RequestMapping(value = "/persons",
produces = { "application/json" },
method = RequestMethod.GET)
public PagedResources<PersonResource> persons(...) {}
Related
My REST API must work with gRPC objects as input parameters.
The most simple example is:
GET http://localhost:8083/api/books?page.number=1&page.size=30
where the proto definition is:
message PagedMessage {
Page page = 1;
}
message Page {
int32 number = 1;
int32 size = 2;
}
The controller is:
#RequestMapping(value = "/api/books")
public class ObjectOps {
#Autowired
private BooksService booksService;
#GetMapping(value = "/")
#ResponseBody
BooksList listBooks(#RequestParam PagedMessage request) {
return booksService.getBooks(request);
}
}
And in the application I have this bean:
#Bean
ProtobufJsonFormatHttpMessageConverter protobufJsonFormatHttpMessageConverter() {
return new ProtobufJsonFormatHttpMessageConverter();
}
The only way it worked for me is to pass the paging information as GET body:
{
"page" : {
"number": 1,
"size": 30
}
}
but it will be great to have the list books method object be populated from the request path parameters.
I think you can just remove the #RequestParam annotation and Spring will populate the object.
Referenced by this answer: https://stackoverflow.com/a/16942352/8075423
I was told that when building RestFul APIs, use nouns and not verbs. I was also told that each DTO gets its own controller. What does my DTO look like in the case that "edit property" and "add property" methods require two different request bodies?
#RestController
#RequestMapping(value = "/property")
public class PropertyController{
#RequestMapping(method = RequestMethod.GET)
//get properties method definition goes here
#RequestMapping(method = RequestMethod.PUT)
// edit property method definition goes here
#RequestMapping(method = RequestMethod.POST)
// add property method definition goes here
}
edit property requires:
{
"userloginid": "3333",
"propertyname": "My edited property name",
"propertyid": "1"
}
add property requires:
{
"userloginid": "3333",
"propertyname": "My new property name"
}
/users/{loginid}/properties/{propertyid} - please consider this endpoint as it is more RESTful
For PUT updates you can consider the endpoint above, and get your userloginid and propertyid from the Path Variables.
In the PUT request PUT /users/3333/properties/1 I would send the following Request Body:
{
"propertyname": "My edited property name"
}
For POST requests to create a new property I would consider sending a Request to this URL /users/{loginid}/properties/ with the same Request Body structure:
{
"propertyname": "My new property name"
}
As you can see I am not sending any ID in the POST request as ID generation for stored objects should happen in the DAO.
The client will receive the ID of the created/updated property in the Response Body:
{
"propertyname": "My updated/created property name",
"propertyid": "1"
}
So from the above examples, I would create two DTOs for handling the output and input situations.
From your json data, your DTO might be
PropertyDTO{
long userloginid;
String propertyname;
long propertyid;
}
So your API will look like
#RestController
#RequestMapping(value = "/property")
public class PropertyController{
#RequestMapping(method = RequestMethod.GET)
public PropertyDTO get(){
return null;
}
#RequestMapping(method = RequestMethod.PUT)
public Boolean update(#RequestBody PropertyDTO dto){
return true;
}
#RequestMapping(method = RequestMethod.POST)
public Boolean insert(#RequestBody PropertyDTO dto){
return true;
}
}
You should create the same DTO with these three properties (userloginid, propertyname, propertyid). But you have to consider that the propertyid can be null. Then when the request paramters are sent, if propertyid is not sent, the parser will create an instance of DTO with propertyid=null; else the parser will create an instance of DTO with propertyid=value_passed_in parameter.
I am trying to figure out if it is possible to pass a JSON object to rest API, Or pass a multiple parameters to that API ? And how to read these parameters in Spring ? Lets assume that the url looks like the below examples :
Ex.1 http://localhost:8080/api/v1/mno/objectKey?id=1&name=saif
Is it valid to pass a JSON object like in the url below ?
Ex.2 http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"}
Questions:
1) Is it possible to pass a JSON object to the url like in Ex.2?
2) How can we pass and parse the parameters in Ex.1?
I tried to write some methods to achieve my goal, but could not find the right solution?
I tried to pass JSON object as #RequestParam
http://localhost:8080/api/v1/mno/objectKey?id=1 There was an unexpected error (type=Unsupported Media Type, status=415). Content type 'null' not supported
http://localhost:8080/api/v1/mno/objectKey/id=1 There was an unexpected error (type=Not Found, status=404). No message available
http://localhost:8080/api/v1/mno/objectKey/%7B%22id%22:1%7D There was an unexpected error (type=Not Found, status=404). No message available
#RequestMapping(value="mno/{objectKey}",
method = RequestMethod.GET,
consumes="application/json")
public List<Book> getBook4(#RequestParam ObjectKey objectKey) {
...
}
I tried to pass the JSON object as #PathVariable
#RequestMapping(value="ghi/{objectKey}",method = RequestMethod.GET)
public List<Book> getBook2(#PathVariable ObjectKey objectKey) {
...
}
I created this object to hold the id parameter and other parameters like name , etc ....
class ObjectKey{
long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
(1) Is it possible to pass a JSON object to the url like in Ex.2?
No, because http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"} is not a valid URL.
If you want to do it the RESTful way, use http://localhost:8080/api/v1/mno/objectKey/1/Saif, and defined your method like this:
#RequestMapping(path = "/mno/objectKey/{id}/{name}", method = RequestMethod.GET)
public Book getBook(#PathVariable int id, #PathVariable String name) {
// code here
}
(2) How can we pass and parse the parameters in Ex.1?
Just add two request parameters, and give the correct path.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.GET)
public Book getBook(#RequestParam int id, #RequestParam String name) {
// code here
}
UPDATE (from comment)
What if we have a complicated parameter structure ?
"A": [ {
"B": 37181,
"timestamp": 1160100436,
"categories": [ {
"categoryID": 2653,
"timestamp": 1158555774
}, {
"categoryID": 4453,
"timestamp": 1158555774
} ]
} ]
Send that as a POST with the JSON data in the request body, not in the URL, and specify a content type of application/json.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.POST, consumes = "application/json")
public Book getBook(#RequestBody ObjectKey objectKey) {
// code here
}
you can pass multiple params in url like
http://localhost:2000/custom?brand=dell&limit=20&price=20000&sort=asc
and in order to get this query fields , you can use map like
#RequestMapping(method = RequestMethod.GET, value = "/custom")
public String controllerMethod(#RequestParam Map<String, String> customQuery) {
System.out.println("customQuery = brand " + customQuery.containsKey("brand"));
System.out.println("customQuery = limit " + customQuery.containsKey("limit"));
System.out.println("customQuery = price " + customQuery.containsKey("price"));
System.out.println("customQuery = other " + customQuery.containsKey("other"));
System.out.println("customQuery = sort " + customQuery.containsKey("sort"));
return customQuery.toString();
}
Multiple parameters can be given like below,
#RequestMapping(value = "/mno/{objectKey}", method = RequestMethod.GET, produces = "application/json")
public List<String> getBook(HttpServletRequest httpServletRequest, #PathVariable(name = "objectKey") String objectKey
, #RequestParam(value = "id", defaultValue = "false")String id,#RequestParam(value = "name", defaultValue = "false") String name) throws Exception {
//logic
}
Yes its possible to pass JSON object in URL
queryString = "{\"left\":\"" + params.get("left") + "}";
httpRestTemplate.exchange(
Endpoint + "/A/B?query={queryString}",
HttpMethod.GET, entity, z.class, queryString);
I am new to Spring and Rest Endpoints.
I have a controller, which accepts #RequestParam and returns a JSON Response.
By default the #RequestParam required = "true", which is how I need it.
I am using Spring 3.1.3
This is my Get Method in the controller:
#Controller
#RequestMapping("/path")
public class MyController{
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = true) final String test) {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
When I send a get with the request param it hits the endpoint , which is how I expect.
Example : path/search/again.do?test=yes
Everything is perfect.
This is where I am having issue:
When I send a Get with that value missing:
Example: path/search/again.do
I get a 400 Bad Request. May be this is correct.
But what I want to achieve is. When the required value is missing in the GET request.
I can send a JSON response as that #RequestParam Value test is missing.
Can anybody guide me how to achieve this.
I am not sure what I am missing.
Thanks in advance.
If you look closely at your code, you'll see that the answer is staring right at you. Just change required to false and you should be good to go. When the user doesn't provide a value for GET parameter test, then you can return a special message.
#Controller
#RequestMapping("/path")
public class MyController {
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = false) final String test) {
if (test == null) {
return new ResponseEntity<String>("test parameter is missing", HttpStatus.OK);
}
else {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
}
Solution 1: You can use custom #ExceptionHandler in your controller, e.g
#ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<?> paramterValidationHandler(HttpServletResquest request){
//validate the request here and return an ResponseEntity Object
}
Solution 2: Would be custom spring ErrorController which I never have tried myself but it possible to override it.
Solution 3: You can write an ControllerAdvice for a global controller exception handling.
Well if you set the parameter test is required. U just can't send the request without that param. Try to change the param required= false and handle the missing param in the method. You can us something likeif(test==null) throw new Exception("Param test missing")
I m actually creating a simple application and I need to have routing pattern identical in multiple case :
/*
* Returns a list of all the root directories accepting query string on name
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> find() {
return directoryService.findAll();
}
/*
* Returns a list of all the root directories accepting query string on name
* #param name Name of the ressources to search. Query string at format : *name*
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
In fact, I dont want to manage criteria request in the same function as findAll one. Is there anyway to handle this case without be forced to manage everything inside the same function ?
Thanks for advance
Try changing the second method #RequestMapping annotation adding params:
#RequestMapping(value = "/directories", method = RequestMethod.GET, params = "name")
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
See also the Spring Documentation for more details.
I'm not quite sure what you are asking, but assuming the decision as to which method to call is based on request parameters (it must be since they're both the same URL and HTTP method), then something like this might help:
#RequestMapping(method=RequestMethod.GET, params={"name"})
public #ResponseBody List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
//do your stuff
}
The inclusion of the params attribute in the #RequestMapping annotation removes the ambiguity in which method to call.
I've also added #ResponseBody to the return type, just in case you want Spring to return the list in the HTTP response.