From 69651c58b7d9f686f8964e7d54909af50c59f296 Mon Sep 17 00:00:00 2001 From: Maxime Delporte Date: Fri, 7 Nov 2025 11:27:45 +0100 Subject: [PATCH] Updating MovieModel's method from internal/data/movies.go file. Create the updateMovieHandler function inside cmd/api/movies.go. Adding the route into routes.go to update a movie. --- cmd/api/movies.go | 63 +++++++++++++++++++++++++++++++++++++++++ cmd/api/routes.go | 1 + internal/data/movies.go | 19 ++++++++++++- 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/cmd/api/movies.go b/cmd/api/movies.go index 0eec7e4..21cadee 100644 --- a/cmd/api/movies.go +++ b/cmd/api/movies.go @@ -87,3 +87,66 @@ func (app *application) showMovieHandler(w http.ResponseWriter, r *http.Request) app.serverErrorResponse(w, r, err) } } + +func (app *application) updateMovieHandler(w http.ResponseWriter, r *http.Request) { + // Extract the movie ID from the URL + id, err := app.readIDParam(r) + if err != nil { + app.notFoundResponse(w, r) + return + } + + // Fetch the existing movie record from the database, sending a 404 Not Found response to the client if we couldn't find a matching record. + movie, err := app.models.Movies.Get(id) + if err != nil { + switch { + case errors.Is(err, data.ErrRecordNotFound): + app.notFoundResponse(w, r) + default: + app.serverErrorResponse(w, r, err) + } + return + } + + // Declare an input struct to hold the expected data from the client + var input struct { + Title string `json:"title"` + Year int32 `json:"year"` + Runtime data.Runtime `json:"runtime"` + Genres []string `json:"genres"` + } + + // Read the JSON request body data into the input struct + err = app.readJSON(w, r, &input) + if err != nil { + app.badRequestResponse(w, r, err) + return + } + + // Copy the values from the request body to the appropriate fields of the movie record. + movie.Title = input.Title + movie.Year = input.Year + movie.Runtime = input.Runtime + movie.Genres = input.Genres + + // Validate the updated movie record, sending the client a 422 Unprocessable Entity response if any checks fail. + v := validator.New() + + if data.ValidateMovie(v, movie); !v.Valid() { + app.failedValidationResponse(w, r, v.Errors) + return + } + + // Pass the updated movie record to our new Update() method + err = app.models.Movies.Update(movie) + if err != nil { + app.serverErrorResponse(w, r, err) + return + } + + // Write the updated movie record in a JSON response + err = app.writeJSON(w, http.StatusOK, envelope{"movie": movie}, nil) + if err != nil { + app.serverErrorResponse(w, r, err) + } +} diff --git a/cmd/api/routes.go b/cmd/api/routes.go index a585357..63f877d 100644 --- a/cmd/api/routes.go +++ b/cmd/api/routes.go @@ -24,6 +24,7 @@ func (app *application) routes() http.Handler { router.HandlerFunc(http.MethodGet, "/v1/healthcheck", app.healthcheckHandler) router.HandlerFunc(http.MethodPost, "/v1/movies", app.createMovieHandler) router.HandlerFunc(http.MethodGet, "/v1/movies/:id", app.showMovieHandler) + router.HandlerFunc(http.MethodPut, "/v1/movies/:id", app.updateMovieHandler) // Return the httprouter instance. // Wrap the router with the panic recovery middleware diff --git a/internal/data/movies.go b/internal/data/movies.go index 7e96582..9506ab8 100644 --- a/internal/data/movies.go +++ b/internal/data/movies.go @@ -109,7 +109,24 @@ func (m MovieModel) Get(id int64) (*Movie, error) { // Update : Updating a specific record in the movies table func (m MovieModel) Update(movie *Movie) error { - return nil + // Declare the SQL query for updating the record and returning the new version number. + query := ` + UPDATE movies + SET title = $1, year = $2, runtime = $3, genres = $4, version = version +1 + WHERE id = $5 + RETURNING version` + + // Create an args slice containing the values for the placeholder parameters. + args := []any{ + movie.Title, + movie.Year, + movie.Runtime, + pq.Array(movie.Genres), + movie.ID, + } + + // Use the QueryRow() method to execute the query, passing in the args slice as a variadic parameter and scanning the new version value into the movie struct. + return m.DB.QueryRow(query, args...).Scan(&movie.Version) } // Delete : Deleting a specific record from the movies table