I am completely new to Reactive Spring Webflux.
I am writing a handler for a Post request which should
Accept Json body(Employee id, name and role),
Fetch some more Employee details from database 1 using id field,
Return Employee json back with additional attributes like age and dept..
My router code is below:
#Bean
-- something like this
POST("/empl/create").and(contentType(APPLICATION_JSON)), emplHandler::getMoreEmplDetails
Post Body:
{
"id":"213"
"name": "John",
"role": "Manager"
}
Model Class looks like this
Public class Employee
{
Public string id;
Public string name;
Public string role;
Public string dept;
Public int age;
}
Handler Code is Below
public Mono<ServerResponse>getMoreEmplDetails(ServerRequest request){
Mono<Employee> np = request.bodyToMono(Employee.class);
np.subscribe(x-> System.out.println("Print Body"+x));
//This returns a MonoOnErrorResume
/* More code should follow here*/
Return Mono.empty()// THIS IS TEMPORARY. I WANT TO RETURN COMPLETE EMPL JSON WITH AGE AND DEPT HERE
};
Problem is I want to print body for debugging purpose but Keep getting MonoOnErrorResume as indicated in comments in handler code. How do I make sure that my Body was received fine by the handler method ??
I was able to use map to log the results.
Mono<Employee> np = request.bodyToMono(Employee.class);
np.map(s->system.out.println(s));
Related
I am developing a Java backend application using Spring Boot. My controller needs to receive this type of object as input with an HTTP POST call:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Input {
private String name;
private String surname;
private String fiscalCode;
}
obviously these data arrive thanks to a JSON made like this:
{
"name":"John",
"surname":"Smith",
"fiscalCode":"XXXXXXXXX"
}
This is an example of a controller handling POST containing this body:
#PostMapping(produces = { "application/json" })
public ResponseEntity<Object> myController(#RequestBody Input myInput) {
// code....
}
The question is: how can I elegantly (without using a switch case or a series of if-else) detect all fields that are "" or null in my myInput object, and return a string that warns for example that "name, surname fields missing"?
What is the best way to do this? I've heard it's okay to use #ControllerAdvice, but I don't know how to do it.
Check out the #Validate annotation.
e.g. https://www.baeldung.com/spring-boot-bean-validation
I have an objects in java backend that i want to change status property on:
#Entity
public class Employee {
#Id #GeneratedValue long id;
private String name;
private String status;
}
I want to set the property status to "Checked" for a targeted object chosen with id with this putmapping:
#PutMapping("/api/users/id")
public Employee changeStatus(#RequestParam Long id)
{
Employee newEmployee = userRepository.getById(id);
newEmployee.setStatus("Checked");
return userRepository.save(newEmployee);
}
I want to do it from my frontend through :
public changeStatus(id: number): Observable<any>
{
return this.http.put<any>(${this.apiServerUrl}/users/id, id)
}
Nothing happens in backend, no errors or anything shows up. What am i missing? I suspect i do something wrong in the frontend call, but i cant figure it out.
Backend-frontend connections seems to work because i can get all data from my backend and see it in frontend with theese two endpoints
Backend:
#RequestMapping("/api/users") public List<Employee> getUsers()
{
return (List<Employee>) userRepository.findAll();
}
Frontend:
public getUsers(): Observable<any>
{
return this.http.get<any>(${this.apiServerUrl}/users)
}
Thanks in advance!
Are you subscribing to this call on the FE ? the angular HttpClient returns an Observable, if you are not subscribing, i.e. if you are not doing something like this:
getUsers().subscribe((data) => {
console.log('whatever');
})
The http request will never be send, that's how observable works, they only get "executed" when someone is "listening"
Seeing how you try to pass id as pathVariable your endpoint should also accept it as such. For that refactor your endpoint. Frontend looks fine.
#PutMapping("/api/users/{id}")
public Employee changeStatus(#PathVariable Long id)
{
Employee newEmployee = userRepository.getById(id);
newEmployee.setStatus("Checked");
return userRepository.save(newEmployee);
}
Remove one extra id from url.
public changeStatus(id: number): Observable<any>
{
const url = this.apiServerUrl + /users/ + id;
return this.http.put<any>(url);
}
Otherwise try to get rid of any types and use strong typing - that's the benefit TypeScript gives us.
i am trying to send nested json object in POST request to my spring REST API.
Object java code
public class TestModel {
private String id;
private String name;
public TestModel(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
Post method code in rest controller
#RequestMapping(value = "/helloPost")
public ResponseEntity<TestModel> helloPost(#RequestBody TestModel t) {
return new ResponseEntity<TestModel>(t, HttpStatus.OK);
}
My postman screenshot
It has to return status 200 ok and object i sent, but it returns 400 bad request permanently.
Please, tell me what am i doing wrong. It was ok when i sent one string(my #RequestBody was string too) but completly not working with custom objects.
P.S
i have added comma, no changes
You missed the "," after the id field in JSON. proper JSON is your case would be below :-
{
"id" : "1",
"name" : "test"
}
It's a malformed json you are sending to the server. You need to add comma to separate elements in json.
Even postman showing wrong icon at the left.
{
"id" : 1,
"name" : "test"
}
Also you need to add setters and default constructor in object model to set those values.
As mentioned in the comment, please add the default constructor for TestModel class. It should resolve the problem.
As an additional step, if the web service is going to accept json as input, then add consumes annotation with content type as application json.
I need to have my Java server receive a PUT request to create a new user from an id and a json body, the URI needs to be like:
/usermanagement/user/$id { "name":john, "type":admin }
Given that I've made a simple Java class and can later convert the JSON to a POJO using Jackson, here's my problem:
How do I specify the PUT request to accept both the id and the JSON body as parameters? So far I've got:
#PUT
#Path("{id}")
#Consumes(MediaType.APPLICATION_JSON)
public String createUser(#PathParam("id") int id){
User user = new User();
User.setId(id);
return SUCCESS_MSG;
}
And this works, but I've had no luck adding the JSON body and having the function parse it. I've tried:
public String createUser(#PathParam("id") int id, String body){
return body;
}
It should return the same input JSON when testing in Postman, however it always returns a "resource not available" error.
I feel there's something obvious that I'm missing here?
As per REST API conventions, a POST method on a uri like /usermanagement/users is what is needed. PUT method is used for updating an existing resource. You can go through this wonderful article on how to design pragmatic RESTful API. http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api.
If you are trying to create a new user, why give it an ID? You have to POST the data such as user name, lastname, email, ... and let the backend generate an ID (like an auto-incremented id, or some UUUID) for this new resource.
For example, in my app, I use a json body for a POST request like below:
{
"loginId": "ravi.sharma",
"firstName": "Ravi",
"lastName": "Sharma",
"email": "myemail#email.com",
"contactNo": "919100000001",
"..." : ".."
}
Moreover, your response should return HTTP-201, after successful creation, and it should contain a location header, pointing to the newly created resource.
Instead of Using String body, use a Class with Member variables name and Type Like this.
public class User {
private String name;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
(This works in Spring Boot Web out-of-box. incase of Spring MVC, you might need to add Jackson dependency): On your Controller , Add #RequestBody Annotation, then Jackson will take care of the un-marshaling of JSON String to User Object.
public String createUser(#PathParam("id") int id, #RequestBody User user){
I have a spring web service method where i want to get a string as a parameter. The string is sent in body of the request. My web service class is:
#Controller
#RequestMapping(value = "/users/{uid}/openchart")
public class OpenChartWebService {
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String saveABC(#PathVariable("uid") Long uid,
#RequestBody String myString) {
System.out.println("sent string is: "+myString);
return "something";
}
}
My request in body is :
{
"name":"Ramesh"
}
But this is not working. This shows "Bad Request" HTTP error(400). How to send a string in a body and how to get a string sent in a body inside webservice method?
As #Leon suggests, you should add the media type to your request mapping, but also make sure you have Jackson on your classpath. You'll also want to change your #RequestBody argument type to something that has a "name" property, rather than just a String so that you don't have to convert it after.
public class Person {
private name;
public getName() {
return name;
}
}
If your data object looked like the above, then you could set your #RequestBody argument to Person type.
If all you want is a String, then perhaps just pass the value of "name" in your request body rather than an object with a name property.