lmngn23
lmngn23

Reputation: 521

Can't invoke the put endpoint in Springboot

I have this code from the front-end (Angular)

   private _baseUrl = "http://localhost:8080/api/v1/professor/";


   getProfessor(id: string): Observable<Professor> {
    const professor = this.http.get<Professor>(this._baseUrl + id);
    return professor;
   }
   addProfessorRating(id: string, rating: Object): void {
    // get the professor, then modify the ratings of them, and make a put request
    this.getProfessor(id).subscribe(professor => {
        let ratings = professor['ratings'];
        ratings.push(rating);
        professor['ratings'] = ratings;
        return this.http.put<void>(this._baseUrl + id, professor, {
            headers: new HttpHeaders({
                'content-type': 'application/json'
            })
        })
    });
}

And this endpoint from the backend (Spring boot):

@PutMapping(path = "/{id}")
public String updateProf(@PathVariable("id") String id, @Valid @NotNull @RequestBody Professor professor) {
    logger.info("updating professor");
    professorService.updateProfessor(id, professor);
    return "Updated professor with id: " + id;
}

However, the endpoint is not invoking as the logger doesn't log anything in the console. I tried with Postman and it did make call to the endpoint. Am I doing anything wrong, I would also provide any info if this post is not specific enough.

UPDATE: I called the addProfessorRating by the onSubmit function from Angular form:

onSubmit(rating: Object) {
    const id = this.route.snapshot.paramMap.get('id');
    this.professorService.addProfessorRating(id, rating);
}

I would appreciate any help.

Upvotes: 0

Views: 95

Answers (1)

Barremian
Barremian

Reputation: 31125

You need to use a RxJS higher order mapping operator (eg. switchMap) to map from one observable (this.getProfessor()) to another (this.http.put()).

Try the following

private _baseUrl = "http://localhost:8080/api/v1/professor/";
addProfessorRating(id: string, rating: Object): void {
  this.getProfessor(id).pipe(        // get the professor, then modify the ratings of them, and make a put request
    switchMap(professor => {
      let ratings = professor['ratings'];
      ratings.push(rating);
      professor['ratings'] = ratings;
      return this.http.put < void > (this._baseUrl + id, professor, {
        headers: new HttpHeaders({
          'content-type': 'application/json'
        })
      });
    })
  ).subscribe(
    res => console.log(res),
    err => console.log(err)
  );
}

Good practice is to return the observable from all functions and subscribe to it in the base function. This allows you to retain the async nature of the calls and use the emitted value from the observable.

addProfessorRating(id: string, rating: Object): Observable<any> {    // <-- return the observable
  return this.getProfessor(id).pipe(        // get the professor, then modify the ratings of them, and make a put request
    switchMap(professor => {
      let ratings = professor['ratings'];
      ratings.push(rating);
      professor['ratings'] = ratings;
      return this.http.put < void > (this._baseUrl + id, professor, {
        headers: new HttpHeaders({
          'content-type': 'application/json'
        })
      });
    })
  );      // <-- don't subscribe yet
}

onSubmit(rating: Object) {
  const id = this.route.snapshot.paramMap.get('id');
  this.professorService.addProfessorRating(id, rating).subscribe(    // <-- subscribe here
    res => {
      console.log(res);
      // other statements that depend on `res`
    },
    err => {
      // also good practice to handle error notifications from HTTP observables
    }
  );
}

Other types of RxJS higher order mapping operators are mergeMap, concatMap and exhaustMap. You could find brief differences between them here.

Upvotes: 2

Related Questions