From 6ef731573b3b5a77a1910846523c0b9b7b756bb8 Mon Sep 17 00:00:00 2001 From: Maxime Delporte Date: Tue, 28 Oct 2025 12:07:04 +0100 Subject: [PATCH] Exporting the validation from cmd/api/movies.go to internal/data/movies.go by creating the ValidateMovie method. Updating createMovieHandler to use our new ValidateMovie method. --- cmd/api/movies.go | 29 ++++++++++------------------- internal/data/movies.go | 24 +++++++++++++++++++++++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/cmd/api/movies.go b/cmd/api/movies.go index 5f11530..cc7fd56 100644 --- a/cmd/api/movies.go +++ b/cmd/api/movies.go @@ -25,28 +25,19 @@ func (app *application) createMovieHandler(w http.ResponseWriter, r *http.Reques return } + // Copy the values from the input struct to a new Movie struct : we're doing this because a client could provide the keys *id* and *version* in their JSON request, and the corresponding values would be decoded without any error into the *ID* and *Version* fields of the *Movie* struct - even though we don't want them to be. + movie := &data.Movie{ + Title: input.Title, + Year: input.Year, + Runtime: input.Runtime, + Genres: input.Genres, + } + // Initialize a new Validator instance v := validator.New() - // Use the Check() method to execute our validation checks. This will add the provided key and error message to the errors maps if the check does not evaluate to true. For example, in the first line we "check that the title is not equal to an empty string". - v.Check(input.Title != "", "title", "must be provided") - v.Check(len(input.Title) <= 500, "title", "must not be more than 500 bytes long") - - v.Check(input.Year != 0, "year", "must be provided") - v.Check(input.Year >= 1888, "year", "must be greater than 1888") - v.Check(input.Year <= int32(time.Now().Year()), "year", "must not be in the future") - - v.Check(input.Runtime != 0, "runtime", "must be provided") - v.Check(input.Runtime > 0, "runtime", "must be a positive integer") - - v.Check(input.Genres != nil, "genres", "must be provided") - v.Check(len(input.Genres) >= 1, "genres", "must contain at least 1 genre") - v.Check(len(input.Genres) <= 5, "genres", "must not contain more than 5 genres") - // Not that we're using the Unique helper in the line below to check that all values in the input.Genres slice are unique - v.Check(validator.Unique(input.Genres), "genres", "must not contain duplicate values") - - // Use the Valid() method to see if any of the checks failed. If they did, then use the failedValidationResponse() helper to send a response to the client, passing in the v.Errors map. - if !v.Valid() { + // Call the ValidateMovie() function and return a response containing the errors if any of the checks fail. + if data.ValidateMovie(v, movie); !v.Valid() { app.failedValidationResponse(w, r, v.Errors) return } diff --git a/internal/data/movies.go b/internal/data/movies.go index fb3f559..9fab01b 100644 --- a/internal/data/movies.go +++ b/internal/data/movies.go @@ -1,6 +1,9 @@ package data -import "time" +import ( + "greenlight.craftr.fr/internal/validator" + "time" +) // Movie /* @@ -19,3 +22,22 @@ type Movie struct { Genres []string `json:"genres,omitempty"` Version int32 `json:"version"` } + +func ValidateMovie(v *validator.Validator, movie *Movie) { + // Use the Check() method to execute our validation checks. This will add the provided key and error message to the errors maps if the check does not evaluate to true. For example, in the first line we "check that the title is not equal to an empty string". + v.Check(movie.Title != "", "title", "must be provided") + v.Check(len(movie.Title) <= 500, "title", "must not be more than 500 bytes long") + + v.Check(movie.Year != 0, "year", "must be provided") + v.Check(movie.Year >= 1888, "year", "must be greater than 1888") + v.Check(movie.Year <= int32(time.Now().Year()), "year", "must not be in the future") + + v.Check(movie.Runtime != 0, "runtime", "must be provided") + v.Check(movie.Runtime > 0, "runtime", "must be a positive integer") + + v.Check(movie.Genres != nil, "genres", "must be provided") + v.Check(len(movie.Genres) >= 1, "genres", "must contain at least 1 genre") + v.Check(len(movie.Genres) <= 5, "genres", "must not contain more than 5 genres") + // Not that we're using the Unique helper in the line below to check that all values in the input.Genres slice are unique + v.Check(validator.Unique(movie.Genres), "genres", "must not contain duplicate values") +}