Travel Adventures API - Creating a REST API using SPRING (Step 6, POST)

Hi there, I have a general question about distinguishing declaring a method used to POST a new entry back to a repository. I want to know if my logic is sound. I am currently working on the Travel Adventures API Project in the Create REST APIs with Spring and Java Skill Path, I am on step 6, trying to create a POST endpoint to add a new entry to the repository. I am declaring the method as a String, and returning a success message to let the user know that their entry has been created. When going through the walkthrough, I noticed the engineer declared this method as an Adventure Object, and returned a newAdventure Object after calling the .save() method on the passed through adventure object. I am also calling the .save() method, but I am not returning the newAdventure object, actually I am not even creating that object I am just writing the line this.adventureRepository.save(adventure);

Are these two methods accomplishing the same thing? Is my object actually being saved to the DB or is the success message misleading? Additionally, if the adventureRepository object is declared as final, doesnt that mean it cannot be edited? See my code below, would love some feedback on this :slight_smile:

package com.codecademy.plants.controllers;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import com.codecademy.plants.entities.Adventure;
import com.codecademy.plants.repositories.AdventureRepository;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;


@RestController
@RequestMapping("/traveladventures")
public class TravelAdventuresController {

  private final AdventureRepository adventureRepository;

  public TravelAdventuresController(AdventureRepository adventureRepo) {
    this.adventureRepository = adventureRepo;
  }

  // Add controller methods below:
@GetMapping()
public Iterable<Adventure> getAdventure(){
Iterable<Adventure> adventures = this.adventureRepository.findAll();
return adventures;
}

@GetMapping(path = "/bycountry/{country}")
public List<Adventure> getByCountry(@PathVariable String country){
return this.adventureRepository.findByCountry(country);

}

@GetMapping(path = "/bystate")
public List<Adventure> getByState(@RequestParam String state) {
  return this.adventureRepository.findByState(state);
}

@PostMapping()
public String addNewAdventure(@RequestBody Adventure adventure){
this.adventureRepository.save(adventure);
return "New adventure saved to the repository";
}

If someone comes across this, I have a second question. How would I accomplish the bonus task, for checking against duplicate entries? I thought iterating through using a for each loop would do the trick, but it does not appear to be working. Here is the code I created for the POST endpoint, but would i have to specify the {id} in the end point and then try to check agains that using the pre defined findbyId method? Thanks!

@PostMapping()
public String addNewAdventure(@RequestBody Adventure adventure){
Iterable<Adventure> adventures = this.adventureRepository.findAll();

for(Adventure newAdventure : adventures){
  
 if(newAdventure == adventure){
  throw new ResponseStatusException(HttpStatus.CONFLICT, "This adventure already exsists");
}
}
Adventure newAdventure = this.adventureRepository.save(adventure);

you can have a hashset of entries that is just for maintaining truth about uniqueness. If you have the entries stored in a db this would be an expensive call so you’re better off querying the db for existence and writing to it if it’s not there.

Thanks! Sorry could you elaborate on this a little bit, what would the logic & syntax look like for querying for the existence? I’m a little bit stumped on this one…

Ok so you have some repository adventureRepository. This keeps state information about the repository. What I mean by that is that at any point, there is some truth about the repository, and its “state” has to be accounted for.

Depending on use-case, this is stored in some sort of database or in-memory… most likely in a database. If it’s in memory you it’s a lot easier, but less flexible and won’t persist if the app stops running.

If it’s in a database (sqlite, postgres, mysql, mongodb, etc), the data could be stored in records.
Whenever your api app loads, it may load the state of the repositories (or that could be loaded just per api call, depends on use case). The loading happens by querying the database with a select statement.

However, that could be a lot of data if you have a ton of stories, which you might not want to do, in which case you can query the database to tell you if a given story exists in the database.

If you don’t have a database, say you have an array, you could search the array of course.
The problem is if the array is big enough, this would mean having to step through every item in the array (worst-case), which is inefficient. If you also kept a HashSet with the adventure record names, querying for the membership in that is amortized constant time (fancy term for incredibly fast and efficient, assuming a good hash function and other caveats that are not worth going into right now).

Here’s documentation for hashset:
https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html

1 Like

This is very helpful thank you!