Quarkus: How to make request #HeaderParam key as Mandatory Key - rest

How to make the employeeId and employeeName both HeaderParam keys as Mandatory in Quarkus
#POST
#Path("/employee")
#Produces(MediaType.APPLICATION_JSON)
public Response SaveEmployeeDetails(#RequestBody Employee employeeObj, #HeaderParam("empId") BigInteger eemployeeId, #HeaderParam("empName") String employeeName) throws Exception {
//Service Layer Code
}

As the JAX-RS specification does not provide a way to do this, your best best is to the quarkus-hibernate-validator extension and add the #javax.validation.constraints.NotNull annotation to each parameter that needs to not be null.

Related

Liferay 7.2 Api Rest Session parameter

I have Liferay 7.2.
I created a module rest.
It is possibile to save a variable in session ad use it in other method?
My idea of code is:
#GET
#Path("/save/paramt")
public String jsonSaveParamRequest() throws Exception {
String json = "xx";
//SAVE IN SESSION json
return "ok";
}
#GET
#Path("/get/paramt")
public String jsonGetParamRequest() throws Exception {
String xx= SESSION VARIABLE json
return xx;
}
Saving state in a HTTP session in a REST API is not recommended and should be avoided. Please refer to the discussions here SO:how-to-understand-restful-api-is-stateless.
Technically, I guess this is possible as you can inject the HttpServletRequest as a method param via #Context HttpServletRequest request to your annotated method and use getSession(). But I am not sure if you can rely on that.

Spring MVC REST not null constraint does not work on missing request param

Not null validation does not work for a case:
#RestController
public class BookController {
#GetMapping("/api/books/search")
public Page<Book> get(#RequestParam(name = "bookId") #Valid #NotNull Long bookId, Pageable pageable) {
.... // #1
}
}
If I call GET http://localhost:8080/api/books/search?bookId=
bookId is null on row #1. It's strange behaviour, cause if I do not provide bookId it fails.
#NotNull validation is not triggered.
#NotNull validation is not triggered.
When you want the validation to be triggered, the controller class must be annotated with #Validated:
#Validated
#RestController
public class BookController {
...
}
Quoting the documentation:
To be eligible for Spring-driven method validation, all target classes need to be annotated with Spring’s #Validated annotation.
The #RequestParam annotation has a required element where the default value is true. It simply indicates that the parameter itself must be present in the URL (either ?id or ?id=), but it doesn't require a non-null value for that parameter. If you need to validate the value of such parameter, then you should use Bean Validation annotations.
Consider, for instance, the following controller method:
#GetMapping("/foo")
public ResponseEntity<Foo> get(#RequestParam("id") Long id) {
...
}
The following request will result in a response with the 400 status code because the id parameter is not present:
GET /foo HTTP/1.1
Host: example.org
On the other hand, the following request is considered to be valid because the id parameter is present (even though there's no value associated with it):
GET /foo?id HTTP/1.1
Host: example.org
To refuse null values, use the #NotNull annotation (and ensure that controller class is annotated with #Validated):
#GetMapping("/foo")
public ResponseEntity<Foo> get(#RequestParam("id") #NotNull Long id) {
...
}
There are different concepts. Method parameters annotated with #RequestParam are by default required. You can set #RequestParam(required = false) to disable this.
Your parameter however is of type Long (object). You can not give it and then by default it will be null (since you did not set a default - like #RequestParam(defaultValue = )).
Best way is to either set a default value or to check for null in your method.

JAX-RS Request Body Validation

We are using JAX-RS to implement a REST API for one of our projects. Requirement is that the users would pass in the request object in JSON format.
Let us assume that we have a method that is invoked on hitting an API endpoint
#POST
#PATH("/api/user")
#Produces("application/json")
#Consumes("application/json")
public CustomResponse methodA(#RequestBody UserInfo userDTO)
Sample Request Object:
{
"firstName":"Test",
"lastName":"Name",
"sno":"A123"
}
UserInfo DTO
private String firstName;
private String lastName;
private String sno;
getters and setters
Now if the user tries to add other parameters to the request object given above (for ex: "age") and invokes api endpoint, we have not been able to intercept and report the same back to the user saying "Invalid parameter age" as it seems that the request is being filtered out for invalid/unknown parameters and not reporting any error as such.
Any thoughts on how this can be addressed?
I was able to identify unrecognized properties by adding following piece of code:
Change the method signature to
public CustomResponse methodA(#RequestBody String reqObj)
and then
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
UserInfo userDTO = mapper.readValue(reqObj, UserInfo.class);
We now see a
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "<>" for any unsupported parameter

how to pass namedQuery parameters in Apache Camel JPA by header?

I have this camel route:
from("direct:getUser")
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
This is my user Entity:
#Entity
#NamedQueries({
#NamedQuery(name="User.findAll", query="SELECT u FROM User u"),
#NamedQuery(name="User.findById", query="SELECT u FROM User u WHERE u.id = :id")
})
public class User{
#Id
private String id;
}
I have tried this route by setting the header:
from("direct:getUser")
.setHeader("id", simple("myid"))
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
But it is not working
Is there any method to set jpa properties by the headers? The camel documentation quote this in parameters option but i don't found the examples
Options: parameters
This option is Registry based which requires the # notation. This
key/value mapping is used for building the query parameters. It is
expected to be of the generic type java.util.Map where
the keys are the named parameters of a given JPA query and the values
are their corresponding effective values you want to select for. Camel
2.19: it can be used for producer as well. When it's used for producer, Simple expression can be used as a parameter value. It
allows you to retrieve parameter values from the message body header
and etc.
I hope it's not too late to answer. In any case I had a similar issue in my project, the client does a HTTP GET with a parameter id, which is used by the JPA query and the result is finally marshalled back to the HTTP client. I'm running camel in a Spring application.
I finally figured out how to achieve it in a reasonably clean way.
This is the RouteBuilder where the route is defined:
#Override
public void configure() throws Exception {
Class dataClass = SomeClass.class;
JacksonDataFormat format = new JacksonDataFormat();
format.setUnmarshalType(dataClass);
String jpaString = String
.format("jpa://%1$s?resultClass=%1$s&namedQuery=q1" +
"&parameters={\"id\":${headers.id}}", dataClass.getName());
from("jetty://http://localhost:8080/test").toD(jpaString) // note the .toD
.marshal(format)
}
And this is the StringToMapTypeConverter class, otherwise camel cannot convert {"id": X} to a map
public class StringToMapTypeConverter implements TypeConverters {
private static final ObjectMapper mapper = new ObjectMapper();
private static JavaType mapType;
static {
mapType = mapper.getTypeFactory().constructMapType(Map.class,
String.class, Object.class);
}
#Converter
public Map<String, Object> toMap(String map) throws IOException {
return mapper.readValue(map, mapType);
}
}
Remember to add it to the context. In Spring is something like:
<bean id="myStringToMapTypeConverter" class="....StringToMapTypeConverter" />
Refs:
http://camel.apache.org/jpa.html
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
http://camel.apache.org/type-converter.html#TypeConverter-Addtypeconverterclassesatruntime

What is the RESTful way of creating/updating multiple resources

Using Spring MVC on the server, we have your basic REST API:
#Controller
#RequestMapping(value="/entities")
public class EntityController
{
//GET /entities
#RequestMapping(method=RequestMethod.GET)
#ResponseBody
public List<Entity> getEntities()
...
//GET /entities/{id}
#RequestMapping(value="/{id}", method=RequestMethod.GET)
#ResponseBody
public Entity getEntity(#PathVariable Long id)
...
//POST /entities
#RequestMapping(method=RequestMethod.POST, consumes="application/json")
#ResponseBody
public Entity createEntity(#RequestBody Entity entity)
...
//PUT /entities
#RequestMapping(method=RequestMethod.PUT, consumes="application/json")
#ResponseBody
public Entity updateEntity(#RequestBody Entity entity)
...
}
This all works just fine. Now I'm wanting to be able to create or update mutliple Entitys with one request. My first thought was to add this:
#RequestMapping(method=RequestMethod.PUT, consumes="application/json")
#ResponseBody
public List<Entity> updateEntities(#RequestBody List<T> entities)
It would have the same URL as the updateEntity but handle lists ([...]). The updateEntity would handle a single object ({...}). However, on server startup I got the following error:
java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'entityController' bean method public java.util.List<foo.bar.Entity> foo.bar.EntityController.updateEntities(java.util.List<foo.bar.Entity>) to {[/entities],methods=[PUT],params=[],headers=[],consumes=[application/json],produces=[],custom=[]}: There is already 'entityController' bean method public foo.bar.Entity foo.bar.EntityController.updateEntity(foo.bar.Entity) mapped.
So, from what I gather, Spring doesn't like two different methods with the same #RequestMapping, even though the #RequestBody is different.
This leads me to two questions. First, am I going about this the correct RESTful way? Am I in line with RESTful principles when I'm doing a PUT to the same URL and just allowing the request body to be a single object or a list? Would there be another correct way of doing this that Spring would like? (Ok, so the first question was actually three...)
The 2nd question is if there is something I can add to the #RequestMapping annotation that would differentiate the two methods enough, but keep the same REST API?
Thanks for any light you can shed on this.
#JsonIgnoreProperties(ignoreUnknown = true) for each model
I have done on this way...with Two model: User and Tree
#RequestMapping(value = "/users/testBean", method = RequestMethod.POST, consumes={"application/json","application/xml"}, produces={"application/json","application/xml"})
public #ResponseBody List<User> testBean(#RequestBody Object object) {
System.out.println("testBean called");
System.out.println(object.toString());
ObjectMapper mapper=new ObjectMapper();
User user =mapper.convertValue(object, User.class);
Tree tree =mapper.convertValue(object, Tree.class);
System.out.println("User:"+user.toString());
System.out.println("Tree:"+tree.toString());
return userService.findAll();
}