I built a REST API Service using Java Spring Cloud / Boot. Firstly, I made a simple class connected to a MongoDB and a controller with service that should allow me to add, delete, update and get all the objects. When using POSTMAN these all work, however when I want to add or update an object using redux and fetch API I get a status 400 and "bad request" error. This seems to have something to do with the JSON I'm sending in the body but it is the exact same format of JSON that is working with for example POSTMAN.
My action in Redux. For simplicity / test purposes I added an object at the top in stead of using the object being sent from the page.
var assetObject = {
"vendor" : "why dis no work?",
"name": "wtf",
"version": "231",
"category" : "qsd",
"technology" : "whatever"
}
export function addAsset(access_token, asset) {
return dispatch => {
fetch(constants.SERVER_ADDRESS + '/as/asset/add',
{
method: 'POST',
credentials: 'include',
headers: {
'Authorization': 'Bearer' + access_token,
'Content-Type': 'application/json'
},
body: assetObject
})
.then(res => dispatch({
type: constants.ADD_ASSET,
asset
}))
}
}
Controller code in Java Spring:
#RequestMapping(method = RequestMethod.POST, path = "/add")
public void addAsset(#RequestBody Asset asset) {
assetService.addAsset(asset);
}
Status ok while doing it in postman:
The error I get when using Redux / Fetch API (I only removed the directory structure because it has company name in it):
Have been stuck on this for a while, any help is much appreciated!
EDIT Asset Object:
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "assets")
public class Asset {
#Id
private String id;
private String vendor;
private String name;
private String version;
private String category;
private String technology;
public Asset() {
}
public Asset(String id,
String vendor,
String name,
String version,
String category,
String technology) {
this.id = id;
this.vendor = vendor;
this.name = name;
this.version = version;
this.category = category;
this.technology = technology;
}
public String getId() {
return id;
}
public String getVendor() {
return vendor;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
public String getCategory() {
return category;
}
public String getTechnology() {
return technology;
}
public void setId(String id) {
this.id = id;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
public void setName(String name) {
this.name = name;
}
public void setVersion(String version) {
this.version = version;
}
public void setCategory(String category) {
this.category = category;
}
public void setTechnology(String technology) {
this.technology = technology;
}
}
your error message says :
; required request body is missing
i think the error happens when your controller method
trying to form an object from the incoming request.
when you are sending the request you have to set each and every field related to the object.
if you are planning on not setting a property you should mark that field with #JsonIgnore annotation.
you can use #JsonIgnore annotation on the variable which will ignore this property
when forming the object as well as when outputing the object.
use #JsonIgnore annotation on the setter method , which i think you should do now since
you are ignoring the id property when making the request.
#JsonIgnore
public void setId(String id) {
this.id = id;
}
and you can return httpstatus code from the controller method,
so that client knows request was successful
#ResponseBody
public ResponseEntity<String> addAsset(#RequestBody Asset asset) {
return new ResponseEntity<String>("your response here", HttpStatus.OK);
}
Related
I am new spring boot developer and i am trying to develope and rest api . when I do it ,I get and issues that my api return two duplicated response in postman .But i haven't code anythiong to get duplicated valuese in my code . the one of duplicate values is my model clase variable and athor one is table's attribute name .
below response in postman
model class
public class person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
private Long id;
#Column(name = "name")
private String Name ;
#Column(name ="surname")
private String Surname;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getSurname() {
return Surname;
}
public void setSurname(String surname) {
Surname = surname;
}
}
repository
#Repository
public interface personRepository extends JpaRepository<person,Long> {
}
controller
#RestController
#RequestMapping("/person")
public class personController {
#Autowired
private personRepository repository;
public personController(personRepository repository) {
this.repository = repository;
}
#GetMapping("/view/list/person")
private List<person> viewperson() {
return repository.findAll();
}
#PostMapping("/insert/person")
private person savePerson(#RequestBody person obj) {
return repository.save(obj);
}
#DeleteMapping("/delete/{id}")
private void delete(#PathVariable Long id) {
repository.deleteById(id);
}
}
application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialec
t
The problem is that you're not following the proper conventions in your naming strategy.
Due to this, Jackson doesn't know that your getters (getSurname(), getName()) are referencing the fields Surname and Name. That's why it serializes both your fields and your getters separately to JSON.
To fix this, you can follow the Java naming conventions and use a lowercase letter for the first character of your fields.
For example:
#Column(name = "name")
private String name; // Change this
#Column(name ="surname")
private String surname; // Change this
This will change your JSON output to:
{
"id": 1,
"name": "bryan",
"surname": "Nicky"
}
If you want to keep your JSON with capital letters, you can use the #JsonProperty annotation:
#JsonProperty("Name") // Add this
#Column(name = "name")
private String name;
#JsonProperty("Surname") // Add this
#Column(name ="surname")
private String surname;
Unrelated to your question, but according to those naming conventions, your classes should start with a capital (eg. Person, PersonController, PersonRepository, ...).
I have created a RESTful webservice using Spring boot to add a record to H2 database but when I send data from postman to my handler method I get null values on the server side and on the response sent to the client side as well, could anybody help me?
Eclipse Snapshot
Postman Snapshot
My Controller Code:
#RestController
public class AlienController {
#Autowired
AlienRepo repo;
#RequestMapping("/")
public String home() {
return"home.jsp";
}
#PostMapping(path="/alien")
public Alien addAlien(Alien alien) {
System.out.println(alien);
repo.save(alien);
return alien;
}
My DAO Class:
#Entity
public class Alien {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int aid;
private String aname;
private String lang;
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid=aid;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname=aname;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang=lang;
}
#Override
public String toString() {
return "Alien Info: Aid=" + aid + ", Aname=" + aname + ", Lang=" +lang;
}
}
My AlienRepository code:
public interface AlienRepo extends JpaRepository<Alien, Integer>{
}
You should use the annotation #RequestBody
public Alien addAlien(#RequestBody Alien alien)
You should inform Spring that you are waiting for a HttpRequest that contains a Body , Spring will automatically deserialize the inbound HttpRequest body onto Java object
Service Class -
package org.sameer.learnSpringBoot.topic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Service;
#Service
public class TopicService {
private List<Topic> topics = new ArrayList<>(Arrays.asList(new Topic("Spring", "Spring Framework", "Description for Spring"),
new Topic("Hibernate", "Hibernate Framework", "Description For Hibernate"),
new Topic("CoreJava", "Core Java Framework", "Description For CoreJava"),
new Topic("Servlets", "Servlets Framework", "Description for Servlets")));
public List<Topic> getAllTopic() {
return topics;
}
public Topic getTopic(String id) {
return topics.stream().filter(t -> t.getId().equals(id)).findFirst().get();
}
public void addTopic(Topic topic) {
topics.add(topic);
}
}
Controller Class -
#RequestMapping(method = RequestMethod.POST ,value="/topics")
public void addTopic(#RequestBody Topic topic) {
topicService.addTopic(topic);
}
Model Class Topic -
package org.sameer.learnSpringBoot.topic;
public class Topic {
private String id;
private String name;
private String description;
public Topic() {
}
public Topic(String id, String name, String description) {
super();
this.id = id;
this.name = name;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
I am not able to post using POSTMAN plugin from chrome.
enter image description here
And Getting the same in Satacktrace -
2018-02-17 15:57:59.841 WARN 4328 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public void org.sameer.learnSpringBoot.topic.TopicController.addTopic(org.sameer.learnSpringBoot.topic.Topic)
2018-02-17 15:58:08.501 WARN 4328 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public void org.sameer.learnSpringBoot.topic.TopicController.addTopic(org.sameer.learnSpringBoot.topic.Topic)
I am learning Spring Boot. I am trying to HTML Put values to my topics page
CAN ANYBODY PLEASE LET ME KNOW WHAT I AM MISSING HERE??? GET WORKS FINE
STS -4.7.1
JRE - 1.8
Your request body is missing so you are getting BAD REQUEST Error. in request header u have set "Content-type" as application/json. There is a tab named body next to it. click on that and provide the json input body for Topic.
{
"id":"102",
"name":"math",
"description":"asdf"
}
I am having a problem marshalling a RequestBody when the parent class has a namespace.
Class:
#XmlRootElement(name = "blah")
public class Test {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
XML:
<blah>
<id>23333</id>
</blah>
Code:
#RequestMapping( value = "/blah", method = RequestMethod.POST, consumes = { MediaType.TEXT_XML_VALUE }, produces = { MediaType.TEXT_XML_VALUE})
public String getBlah( #RequestBody Test request ) throws Exception
{
assert(null != request.getId());
return "blah";
}
This works fine. However, if I use #XmlRootElement(name = "blah", namespace="home") on the class, and <blah xmlns="home"> in the request, the Test class constructs, but it's ID value is never set.
I'm at a loss.
Before public void setId method add annotation #XmlElement
My first post so please go easy on me..
I am currently writing a hospital rostering web application in BackboneJS + JAX-RS. It has been ok until now but I can't for the life of me work this one out...
In my Group model I have a Users collection.
This is returned as a List<User> from JAX and User has the #XmlRootElement annotation on it.
But when I call fetch it fills the Group model with an array of User models instead of a Users collection.
Is there a way to tell JAX to return my list of User models as a Users collection?
Any help appreciated!
EDIT:
Group model in Backbone:
window.Group = Backbone.Model.extend({
urlRoot: "api/groups",
defaults: {
name: ''
},
validate: function(attrs){
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill in the name field.'});
}
if(!attrs.users || attrs.users.length == 0){
errors.push({name: 'users', message: 'Please add at least 1 user.'});
}
return errors.length > 0 ? errors : false;
}
});
Group model in Java:
package org.jakeduncandev.roster;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Group {
private int id;
private String name;
private int ownerid;
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOwnerid() {
return ownerid;
}
public void setOwnerid(int ownerid) {
this.ownerid = ownerid;
}
}
JSON returned:
"groups":[{"name":"mates","id":71,"users":[{"id":6,"password":"<PASSWORD>","email":"<EMAIL>","firstName":"Jake","lastName":"Duncan"},{"id":7,"password":"<PASSWORD>","email":"<EMAIL>","firstName":"alec","lastName":"stearn"}],"ownerid":0}]
SOLVED!
I added a parse method to my Group model. And then when I was instantiating my collection I used the option: {parse: true} and then it calls the parse method for each model.
Thanks for your help everyone and to user10 for suggesting overriding the parse method!
parse: function(response){
response.users = new window.Users(response.users);
return response;
}