liveBook · Manning

Validation

As explained in Learn Go with Pocket-Sized Projects

Input validation is the process of checking submitted data against required formats, types, and value constraints before processing it.

Validation checks data before processing and keeps invalid values out of business operations. Place rules where every caller receives protection: the domain validates its own entities, while an API translates failures into transport-level responses. section 10.3.1 section 11.4.2

A practical validation design separates responsibilities:

  • Validate and complete entities in the domain so direct callers cannot bypass required rules or defaults. section 10.3.1
  • Return a typed invalid-input error containing the field and reason instead of coupling business code to gRPC status codes. section 10.3.1
  • Map invalid input to gRPC INVALID_ARGUMENT at the API layer; the domain remains unaware of the transport. section 10.3.1
  • Add an early HTTP safety check when parsing form data, while retaining backend protection against invalid or hostile requests. section 11.4.2

Validating and completing a habit

Trim the name and reject an empty result; default a zero weekly frequency to one; generate a missing ID and creation time; return the completed entity or InvalidInputError. section 10.3.1

Validation functions in table-driven tests

Store a validate func(t *testing.T, got money.Amount, err error) in each test case. Each case can check the error, the value, or whichever result matters, while centralizing assertion behavior in the test table. section 6.1.1

Listing 10.13 internal/habit/create.go: Validate/complete entity
// validateAndCompleteHabit fills the habit with values that we want in 
// our database.
// Returns InvalidInputError. #1
func validateAndCompleteHabit(h Habit) (Habit, error) {
    // name cannot be empty
    h.Name = Name(strings.TrimSpace(string(h.Name))) #2
    if h.Name == "" {
        return Habit{}, InvalidInputError{ #3
            field: "name", reason: "cannot be empty"}
    }

    if h.WeeklyFrequency == 0 {
        h.WeeklyFrequency = 1 #4
    }

    if h.ID == "" { 
        h.ID = ID(uuid.NewString()) #5
    }

    if h.CreationTime.Equal(time.Time{}) {
        h.CreationTime = time.Now()
    }

    return h, nil
}

Inspect the Go implementation that trims names, rejects empty input, applies defaults, creates identifiers, and reports typed validation errors. section 10.3.1

Listing 11.34 create.go: Parsing form values
// create takes a JSON request and creates a Habit from it,
// then redirects to index.
func (s *Server) create(w http.ResponseWriter, r *http.Request) {
    habitName := r.FormValue("habitName") #1
    weeklyFreq, err := strconv.Atoi(
        r.FormValue("habitFrequency")) #2
    if err != nil {...}

    // call client

    // redirect to index
    http.Redirect(w, r, "/", http.StatusSeeOther) #3
}

Inspect the HTTP handler that reads form values, parses weekly frequency with strconv.Atoi, and continues through the backend call. section 11.4.2

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Works through normalization, rejection, defaults, typed errors, transport mapping, parsing, and focused tests; it stops short of a validation library implementation.
Examples
Uses money conversion tests, habit creation, whitespace-only names, missing defaults, gRPC status codes, and HTTP form parsing.
What it assumes
Assumes Go testing, functions, structs, HTTP handlers, and gRPC basics while demonstrating validation from concrete implementations.
What you can do after
Build it from scratch by validating domain entities, returning typed errors, testing outcomes, and mapping failures at HTTP or gRPC boundaries.
How it connects
Connects validation with domain-driven design, typed errors, table-driven testing, HTTP, gRPC, Protobuf, and API layering.

Also explained in

Compare how 30 books explain validation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.