The .save
method from the CrudRepository
interface can be used both for creating new entries in the database as well as updating existing entries.
A common flow is to fetch an entry from the database by its ID, update some attribute of the entry, and then call .save
again to persist the change.
Like how GET
requests are used for reading entries from the database, and POST
requests are used for creating new entries in the database, convention dictates that you should use PUT
requests to update entries in the database.
Here’s what a PUT
endpoint to update a Person
would look like:
@PutMapping("/people/{id}") public Person updatePerson(@PathVariable("id") Integer id, @RequestBody Person p) { Optional<Person> personToUpdateOptional = this.personRepository.findById(id); if (!personToUpdateOptional.isPresent()) { return null; } // Since isPresent() was true, we can .get() the Person object out of the Optional Person personToUpdate = personToUpdateOptional.get(); if (p.getName() != null) { personToUpdate.setName(p.getName()); } if (p.getAge() != null) { personToUpdate.setAge(p.getAge()); } if (p.getEyeColor() != null) { personToUpdate.setEyeColor(p.getEyeColor()); } Person updatedPerson = this.personRepository.save(personToUpdate); return updatedPerson; }
In this example, the updatePerson
method takes an Integer id
as path parameter and a Person p
as the request body.
The id
path parameter is used in the call to this.personRepository.findById
to find the Person
entry in the PEOPLE
table that we wish to update.
We first check if the id
existed in the database with the .isPresent()
method on the Optional<Person> personToUpdateOptional
. If it was not present, that meant the id
did NOT exist in the database, so the method terminates early by returning null
to the response body.
Otherwise, if .isPresent()
was NOT false, we can proceed to .get()
the underlying Person
object out of the Optional
and use it for the rest of the method.
The Person
object passed in the request body is used to store the new field values that should be used to update the targeted entry. It does not need to have ALL the fields that a Person
has. When Spring Boot (via Jackson) converts the request body to a Person
object, it simply sets any fields that are missing to null
. Because of this, we are able to use a single endpoint to update any field of the Person
. We can use if
statements to update a field of the target database entry ONLY IF the corresponding field in the request body object was not null.
Lastly, we call the CrudRepository
.save
method to persist the changes that we made to the person. We return the output of the .save
method (updatedPerson
) to the user in the response body, so that they can see how the target entry was updated.
Let’s create a similar PUT
endpoint for our plants application.
Instructions
Like you did before, start by creating a method in the PlantController
, updatePlant
. Don’t add any of the Spring annotations just yet. Your updatePlant
method should accept an Integer id
and a Plant p
. It should return a Plant
. Declare this method and have it return null
for the time being.
Now, add logic into this method that uses the plantRepository
to find the plant with the specified id
:
- Save it into a variable
Optional<Plant> plantToUpdateOptional
. - Then, use the
.isPresent()
and.get()
methods on theplantToUpdateOptional
to add anif
statement that will terminate the method early andreturn null;
if theid
could not be found in the database. - Otherwise, your method should store the found
Plant
in a variable calledplantToUpdate
. For now, return thisplantToUpdate
so your code can compile.
Similar to the Person
example, use if
statements to conditionally check if the fields of p
are null
, and (if they are not), use the “setter” methods of plantToUpdate
to update the fields that have been provided in the request. The fields you should check are: name
, quantity
, wateringFrequency
, and hasFruit
.
After all the if
statements, add the line that will save our updated plant to the database, and store the output in a variable named updatedPlant
. Return the updatedPlant
.
Before testing this method, you’ll need to add all the appropriate Spring annotations. Add the annotations that:
- Make this method the handler for a
PUT
endpoint at"/plants/{id}"
- Make the
Integer id
parameter a path parameter - Make the
Plant p
parameter the request body
Time to test out your new functionality! Use curl
to submit a PUT
request to update the quantity of the "Calla Lily"
plant to 36
, and update the wateringFrequency
to every 3
days instead of every 4
.
To get the id
of the "Calla Lilly"
that we wish to update, try using your GET /plants
endpoint first!