search

Home  >  Q&A  >  body text

POST request works fine when using Postman but not when using React axios and Spring Boot backend

From the react console I get the error "Unable to load resource: The server responded with status 500 ()" pointing to the url ":8080/api/review-add"

From the Spring Boot backend, I get the error message "not-null property reference null or transient value: com.reactspringboot.bookclubbackend.entity.Review.account"

The problem is when doing a POST request in Postman I don't get an error and the object is posted to the database.

This is the file from the Spring Boot backend:

Forum.java

@Entity
@Table(name="Forum")
public class Forum {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private long id;

    @Column(name="book_name")
    private String bookName;

    @Column(name="book_image")
    private String bookImage;

    @Lob
    @Column(name="description")
    private String description;


    @OneToMany(mappedBy = "forum", cascade = CascadeType.ALL)
    private List<Review> reviews;

    public Forum() {
    }

    public Forum(String bookName, String bookImage, String description, List<Review> reviews) {
        this.bookName = bookName;
        this.bookImage = bookImage;
        this.description = description;
        this.reviews = reviews;
    }

    public long getId() {
        return id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookImage() {
        return bookImage;
    }

    public void setBookImage(String bookImage) {
        this.bookImage = bookImage;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    // using 'JsonProperty' to prevent infinite recursion
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    public List<Review> getReviews() {
        return reviews;
    }

    public void setReviews(List<Review> reviews) {
        this.reviews = reviews;
    }
}

Account.java

@Entity
@Table(name="account")
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private long id;

    @Column(name="account_name")
    private String accountName;

    @Column(name="password")
    private String password;

    @Column(name="email")
    private String email;

    @Column(name="profile_image")
    private String profileImage;

    @Column(name="role")
    private String role;

    @Column(name="date_joined")
    @CreationTimestamp
    private Date dateJoined;


    @OneToMany(mappedBy = "account", cascade = CascadeType.ALL)
    private List<Review> reviews;

    public Account() {
    }

    public Account(String accountName, String password, String email, String profileImage, String role, Date dateJoined, List<Review> reviews) {
        this.accountName = accountName;
        this.password = password;
        this.email = email;
        this.profileImage = profileImage;
        this.role = role;
        this.dateJoined = dateJoined;
        this.reviews = reviews;
    }

    public long getId() {
        return id;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getProfileImage() {
        return profileImage;
    }

    public void setProfileImage(String profileImage) {
        this.profileImage = profileImage;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public Date getDateJoined() {
        return dateJoined;
    }

    public void setDateJoined(Date dateJoined) {
        this.dateJoined = dateJoined;
    }

    // using 'JsonProperty' to prevent infinite recursion
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    public List<Review> getReviews() {
        return reviews;
    }

    public void setReviews(List<Review> reviews) {
        this.reviews = reviews;
    }
}

Review.java

@Entity
@Table(name="review")
public class Review {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private long id;

    @Column(name="date_posted")
    @CreationTimestamp
    private Date datePosted;

    @Lob
    @Column(name="comment")
    private String comment;

    @Column(name="star_rating")
    private double starRating;


    //@JsonIgnore
    @ManyToOne
    @JoinColumn(name = "account_id",nullable = false, insertable = true, updatable = true)
    private Account account;


    //@JsonIgnore
    @ManyToOne
    @JoinColumn(name = "forum_id",nullable = false, insertable = true, updatable = true)
    private Forum forum;


    public Review() {
    }

    public Review(Date datePosted, String comment, double starRating, Account account, Forum forum) {
        this.datePosted = datePosted;
        this.comment = comment;
        this.starRating = starRating;
        this.account = account;
        this.forum = forum;
    }

    public long getId() {
        return id;
    }

    public Date getDatePosted() {
        return datePosted;
    }

    public void setDatePosted(Date datePosted) {
        this.datePosted = datePosted;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public double getStarRating() {
        return starRating;
    }

    public void setStarRating(double starRating) {
        this.starRating = starRating;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public Forum getForum() {
        return forum;
    }

    public void setForum(Forum forum) {
        this.forum = forum;
    }
}

ReviewRepository.java

@CrossOrigin(origins = "http://localhost:3000")
public interface ReviewRepository extends JpaRepository<Review, Long> {


    @Query(value = "SELECT * FROM Review r where r.forum_id = :forum_id", nativeQuery = true)
    public List<Review> getReviewsUsingForumId(@Param("forum_id") Long forum_id);
}

ReviewController.java

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/")
public class ReviewController {

    @Autowired
    private ReviewRepository reviewRepository;


    // create review rest api
    //@CrossOrigin(origins = "http://localhost:3000")
    @PostMapping("/review-add")
    public Review createReview(@RequestBody Review review) {
        return reviewRepository.save(review);
    }

    @GetMapping("/forum-reviews/{forumId}")
    public List<Review> getReviewsByForumId(@RequestBody @PathVariable Long forumId) {
        return reviewRepository.getReviewsUsingForumId(forumId);
    }
}

From React frontend

PostComponent.js

function PostComponent() {

    // right now only using static data for testing
    const [review, setReview] = useState({datePosted: "2023-07-26", comment: "", 
                                          starRating: 5.0,
                                          account: {
                                            id: 1
                                          },
                                          forum: {
                                            id: 1
                                          }});
    
    const postURL = "http://localhost:8080/api/review-add";

    function changeHandler (event) {    
        setReview({comment: event.target.value});
    }

    function submit(event) {
        event.preventDefault();
        axios.post(postURL, review)
          
    }

    useEffect(() => {
        console.log(review.comment)
    }, [review]);

    return ( 
        <div>
            <div className="container">
                <h2>Post Review</h2>
                <form onSubmit={(event) => submit(event)}>
                    <div className="form-group">
                        <label>Comment</label>
                        <input placeholder="Commet here" name="comment" className="form=control"
                            value={review.comment} onChange={changeHandler}/>
                    </div>
                    <button>Submit</button>
                </form>
            </div>
        </div>
    ) 
}

export default PostComponent;

In the postman body I select raw and set to JSON and when I use this POST request to the "review" entity it works:

{
    "datePosted": "2023-07-26",
    "comment": "From postman.",
    "starRating": 5.0,
    "account": {
        "id": 1
    },
    "forum": {
        "id": 1
    }
}

The forum with id 1 and the account with id 1 exist in the database.

If anyone can help me or point me to a solution to this problem I would be very grateful. I've been stuck with this problem for days and I'm running out of ideas.

P粉208469050P粉208469050264 days ago574

reply all(1)I'll reply

  • P粉254077747

    P粉2540777472024-04-06 00:44:01

    If the server expects to receive the entire payload:

    {
        "datePosted": "2023-07-26",
        "comment": "From postman.",
        "starRating": 5.0,
        "account": {
            "id": 1
        },
        "forum": {
            "id": 1
        }
    }

    The server will not receive it after you perform the following operations:

    setReview({comment: event.target.value});

    The server will only receive:

    {
        "comment": "From postman."
    }

    When you only want to update one property in the state, the update still needs to include the rest of the object to preserve the entire object:

    setReview({...review, comment: event.target.value});

    or:

    setReview(r => ({...r, comment: event.target.value}));

    BTW...your browser debugging tools can help you narrow down to this exact problem. You can observe the payload in the AJAX request being sent, see that it's not what you expect, and immediately rule out all server-side code as the cause of the problem and start focusing on client-side debugging.

    reply
    0
  • Cancelreply