Search and navigate

Pages

Start HereRoadmapTutorialsCheatsheetInterview QuestionsResources

Published tutorials

Building a REST API with Go: The Complete TutorialGeneric Functions in Go: Writing Reusable CodeGo Benchmarking: Measuring Performance with testing.BGo Channels: Communication Between GoroutinesGo Constraints: comparable, Ordered and Custom SetsGo Context: Cancellation, Deadlines, and Request ValuesGo HTTP Client: Timeouts, JSON, and Reliable RequestsGo HTTP Middleware: Build a Production ChainGo Interview Questions: 25 Answers That Show UnderstandingGo Mutex: Protecting Shared State from Race ConditionsGo net/http: Build an HTTP Server from ScratchGo select Statement: Multiplexing Channels ExplainedGo Tools You Need for a Reliable Development LoopGo Tutorial: From First Program to Backend FoundationsGo Type Parameters: Syntax and Constraints ExplainedGo Worker Pool Pattern: Bounded Concurrency at ScaleGo's Type System Deep Dive: Static Typing Done RightGolang Compilation and Execution ExplainedGolang File Structure for Modules and ApplicationsGolang Hello World and Your First Go ProgramGolang IDEs: Choose an Editor for Your WorkflowGolang Interfaces: What They Are and How to Use ThemGoroutine Leaks in Go: How to Detect and Prevent ThemGoroutines in Go: Concurrency Without LeaksHow to Download and Install Golang SafelyHow to Learn Golang with a Focused Study PlanIntegration Testing in Go: Testing Real BoundariesJSON in Go: Encoding, Decoding, and ValidationLearn Golang with a Practical Beginner CourseMocking in Go: Test Doubles Without Magicsync.WaitGroup in Go: Coordinating Multiple GoroutinesTable-Driven Tests in Go: The Idiomatic WayTesting in Go: Table Tests, HTTP, Fakes, and CoverageWhat Is Go and How Does a Go Program Work?Why Learn Golang and What Is Go Used For?Writing Unit Tests in Go: A Practical Guide
Open full search and filters →

JSON in Go: Encoding, Decoding, and Validation

Encode and decode JSON safely in Go with struct tags, validation, unknown-field checks, and HTTP examples.

Standard-library lessonGo requirement: Go 1.21+How tutorials are checked
Web & APIs · Lesson 1Saved in this browser. No account required.

Verification (10 August 2026): Self-contained runnable examples were compile-tested with Go 1.26.5 on Windows/amd64. Multi-file or contextual snippets and intentional compiler-error demonstrations were checked separately in the repository verification matrix.

Go’s encoding/json package maps JSON values to structs, maps, slices, and primitive types. For APIs, structs provide the clearest contract.

Encode a struct

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email,omitempty"`
}

data, err := json.Marshal(User{ID: 1, Name: "Ada"})

omitempty removes a field when it has its zero value. Avoid using it when clients must distinguish “not supplied” from an explicit zero.

Decode request JSON strictly

func decodeJSON(r *http.Request, dst any) error {
	dec := json.NewDecoder(http.MaxBytesReader(nil, r.Body, 1<<20))
	dec.DisallowUnknownFields()
	if err := dec.Decode(dst); err != nil {
		return err
	}
	if dec.Decode(&struct{}{}) != io.EOF {
		return errors.New("body must contain one JSON value")
	}
	return nil
}

In a real handler, pass the ResponseWriter to MaxBytesReader. Limiting the body prevents an oversized request from consuming unbounded memory. Rejecting unknown fields catches client typos instead of ignoring them.

Validate after decoding

JSON decoding proves that input has the correct representation, not that it is acceptable business data.

type CreateUser struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

func (in CreateUser) Validate() error {
	if strings.TrimSpace(in.Name) == "" {
		return errors.New("name is required")
	}
	if _, err := mail.ParseAddress(in.Email); err != nil {
		return errors.New("email is invalid")
	}
	return nil
}

Write JSON responses consistently

func writeJSON(w http.ResponseWriter, status int, value any) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	return json.NewEncoder(w).Encode(value)
}

Set headers before calling WriteHeader. Do not expose raw internal errors in public JSON responses; map them to stable error codes and log the detailed cause separately.

Numbers and optional fields

Decoding into any converts JSON numbers to float64 by default. Call Decoder.UseNumber when exact numeric representation matters. Use pointer fields or a custom optional type when an update endpoint must distinguish an omitted field from a supplied zero value.