Golang / GoLang Production Patterns and Web Standards Interview Questions
1. Why does Go treat errors as values instead of using exceptions, and what are the advantages?
Go deliberately chose to make errors ordinary values rather than using a try-catch exception mechanism. The error interface has exactly one method: type error interface { Error() string } Any function that can fail returns an error as its last return value. The caller must explicitly handle or pr...
2. How do you wrap errors in Go 1.13+ and use errors.Is and errors.As for inspection?
Go 1.13 introduced the %w verb in fmt.Errorf and the errors.Is / errors.As functions to create and inspect error chains. Wrapping preserves the original error while adding context — callers can still check for specific error types or sentinel values anywhere in the chain. import "errors" // Senti...
3. What are the best practices for defining custom error types in Go?
Custom error types are used when callers need to inspect error details beyond a simple message. The key decision is whether to use a pointer receiver (most common for structs) or a value receiver, and whether to implement the optional Unwrap() method to participate in the error chain. // Pattern ...
4. What is context.Context in Go, what does it carry, and how do you create one?
context.Context is Go's standard mechanism for propagating three things across API boundaries and goroutine boundaries: cancellation signals , deadlines/timeouts , and request-scoped values . Every blocking or long-running function should accept a Context as its first parameter. // The full conte...
5. How does context propagate through an HTTP request lifecycle in Go?
Since Go 1.7, every *http.Request carries a context accessible via r.Context() . This context is cancelled when the client disconnects or the server shuts down. Middleware and handlers should pass this context to all downstream calls — database queries, outbound HTTP calls, gRPC — so they all can...
6. What are the best practices and anti-patterns for using context.WithValue?
context.WithValue should be used sparingly — only for request-scoped data that crosses API boundaries and would be impractical to pass as explicit parameters. It is not a general-purpose parameter-passing mechanism. // ANTI - PATTERN: using a plain string as a context key ctx = context . WithValu...
7. How do you build a production-ready HTTP server using Go's standard net/http package?
Go's net/http package provides a production-capable HTTP server out of the box. Unlike Node.js or Python frameworks, you rarely need a third-party framework for basic HTTP serving — the standard library handles routing, TLS, graceful shutdown, and concurrent request handling. package main import ...
8. What is the standard Go HTTP middleware signature and how do you chain multiple middleware?
Go middleware follows a consistent adapter pattern: a function that accepts an http.Handler and returns a new http.Handler that wraps it. The signature func(http.Handler) http.Handler is the community standard — used by virtually every Go HTTP library. // The standard middleware type type Middlew...
9. How has http.ServeMux evolved in Go 1.22 and what routing patterns does it support?
Go 1.22 significantly upgraded http.ServeMux with method-based routing, path parameters, and wildcard matching — reducing the need for third-party routers in many applications. mux := http.NewServeMux() // Go 1.22+ enhanced routing patterns: // Method + exact path mux.HandleFunc("GET /health", fu...
10. How do you encode and decode JSON in Go and what are the common pitfalls?
Go's encoding/json package provides json.Marshal / json.Unmarshal for byte slices and json.NewEncoder / json.NewDecoder for streams. The stream-based API is preferred for HTTP handlers since it avoids loading the full body into memory. // Struct tags control JSON field names and omission type Use...
11. What are the rules for writing HTTP responses correctly in Go handlers?
The http.ResponseWriter interface has ordering rules that are easy to violate, leading to subtle bugs where headers are silently lost or the response is malformed. // http . ResponseWriter interface: // type ResponseWriter interface { // Header() http . Header // returns the header map (modify be...
12. How do you implement dependency injection in Go without a framework?
Go's idiomatic approach to dependency injection is constructor-based: pass dependencies as arguments to constructors that return concrete types. This is simpler, more testable, and more readable than reflection-based DI frameworks. // Define dependencies as interfaces (for testability) type UserR...
13. How do you implement structured logging in Go using the slog package?
log/slog was added to the standard library in Go 1.21 as the official structured logging solution. It produces machine-readable output (JSON or key-value pairs) and supports levels, attributes, and handler customisation. import "log/slog" // Default logger â uses text format to stderr slog . In...
14. What are the idiomatic Go patterns for managing application configuration?
Go applications typically load configuration from environment variables (twelve-factor app pattern), config files, or a combination. The idiomatic approach is to load all configuration at startup, validate it, and inject it into components as a struct — not read environment variables throughout t...
15. How do you interact with a SQL database in Go using the standard database/sql package?
Go's database/sql package provides a driver-agnostic interface for SQL databases. It manages a connection pool automatically. The key patterns are: always close rows, always use parameterised queries to prevent SQL injection, and pass context to every query. import ( "database/sql" _ "github.com/...
16. How do you implement graceful shutdown of an HTTP server in Go?
Graceful shutdown means: stop accepting new connections, wait for in-flight requests to complete, then exit. This prevents data loss and connection resets for clients whose requests are mid-flight when a deployment or restart occurs. func main() { srv := & http.Server{ Addr: ":8080" , Handler: bu...
17. How do you test HTTP handlers in Go without starting a real server?
Go's net/http/httptest package provides httptest.NewRecorder() (a fake ResponseWriter ) and httptest.NewServer() (a real TCP server on a random port) for testing HTTP code without network overhead. import ( "net/http/httptest" "testing" ) // Unit test: test handler in isolation with mock dependen...
18. What are table-driven tests in Go and why are they the preferred testing pattern?
Table-driven tests define multiple test cases as a slice of structs, then iterate over them running each case. This is Go's idiomatic testing pattern — it reduces duplication, makes it easy to add new cases, and provides clear failure messages identifying which case failed. func divide(a, b float...
19. How do you write testable Go code using interfaces and mocks without a framework?
Go's implicit interface satisfaction means any struct with the right methods satisfies an interface — no registration or code generation required. This makes hand-written mocks straightforward, readable, and dependency-free. // Interface in the consumer package (not the producer) type EmailServic...
20. How do you implement rate limiting in a Go HTTP server?
Rate limiting protects services from overload. Go provides the token bucket algorithm via golang.org/x/time/rate . Production implementations typically rate-limit per client IP or API key, not globally. import "golang.org/x/time/rate" // Global limiter (simple, not per - client) var globalLimiter...
21. How do you implement CORS correctly in a Go HTTP server?
Cross-Origin Resource Sharing (CORS) is required when a browser-based frontend on one domain calls an API on a different domain. Go has no built-in CORS support — you implement it as middleware or use a library like rs/cors . // Manual CORS middleware (for learning â use a library in production...
22. How and when should you use panic and recover in production Go code?
The Go convention is clear: panics are for unrecoverable programmer errors (nil pointer dereference, index out of bounds, type assertion failure). Libraries should never let panics propagate to callers — they convert panics to errors at the public API boundary. // Library pattern: convert interna...
23. How do you manage environment-specific settings and feature flags in Go?
Production Go applications distinguish between environments (development, staging, production) through configuration — not through build tags or conditional compilation. Feature flags allow gradual rollouts without redeployment. // Environment detection via config type Environment string const ( ...
24. How do you implement health check and readiness endpoints for a Go service?
Health checks are mandatory for Kubernetes deployments. A liveness probe tells Kubernetes whether the process is running (should it restart?). A readiness probe tells Kubernetes whether the pod should receive traffic (is it ready to serve?). type HealthChecker struct { db * sql.DB cache * redis.C...
25. How do you add observability (metrics and distributed tracing) to a Go service?
Production Go services expose Prometheus metrics and OpenTelemetry traces. Both integrate with Go's standard HTTP server and context-based propagation. // Prometheus metrics with the standard prometheus / client_golang library import ( "github.com/prometheus/client_golang/prometheus" "github.com/...
26. How do build tags work in Go and when do you use them?
Build constraints (build tags) allow you to include or exclude source files from compilation based on OS, architecture, Go version, or custom conditions. They are used for platform-specific code and integration test separation. // Modern syntax (Go 1.17 + ) â // go:build directive // Must be th...
27. What are the best practices for using Go's HTTP client in production?
The default http.DefaultClient is not suitable for production — it has no timeouts, uses a shared transport, and cannot be instrumented. Production code creates dedicated clients with explicit configuration. // Production HTTP client â never use http.DefaultClient in libraries func newHTTPClien...
28. What patterns make HTTP error handling consistent and DRY in Go?
Go HTTP handlers cannot return errors — the function signature is func(http.ResponseWriter, *http.Request) . Several patterns solve this: the custom handler type, the handler error interface, or a response helper pattern. // Pattern 1: custom handler type that returns error type HandlerFunc func(...
29. What are the common API versioning strategies in Go HTTP services?
API versioning allows a service to evolve without breaking existing clients. Go supports several approaches, each with different trade-offs in URL clarity, header complexity, and routing ease. // Strategy 1: URL path versioning (most common, most explicit) mux.HandleFunc( "GET /v1/users/{id}" , v...
30. How do Go programs handle OS signals and interact with the operating system?
Go programs receive OS signals through the os/signal package. Signals are delivered to Go channels via signal.Notify . Common production uses: graceful shutdown (SIGTERM), config reload (SIGHUP), and heap dump triggering (SIGUSR1). import ( "os" "os/signal" "syscall" ) // Standard graceful shutdo...
31. How do you profile a Go service in production using pprof?
Go ships a built-in profiler accessible via HTTP when you import net/http/pprof . Adding this to a running service provides CPU profiles, heap snapshots, goroutine dumps, and block profiles without restarting the service. // Add to main or a dedicated debug server import _ "net/http/pprof" // sid...
32. How does Go's module system work and what are the key commands?
The Go module system (introduced in Go 1.11, stable in Go 1.13) manages dependencies through a go.mod file. It replaced GOPATH-based dependency management and provides reproducible builds through cryptographic checksums in go.sum . // go.mod anatomy module github.com / myorg / myservice go 1.22 r...
33. How do you validate HTTP request inputs in Go without a framework?
Input validation is a layered concern: structural validation (is the JSON well-formed?), field validation (are required fields present, within range?), and business validation (does the email already exist?). Go handles this without a framework using explicit checks and helper functions. // Reque...
34. How do you implement streaming HTTP responses in Go?
Streaming is useful when the response is large, generated incrementally, or delivered in real-time (server-sent events, file downloads). Go's http.Flusher interface allows the handler to push buffered data to the client without waiting for the full response. // Check if ResponseWriter supports fl...
35. How do you write and interpret Go benchmarks?
Go's testing package has built-in benchmark support. Benchmarks are functions with signature func BenchmarkXxx(b *testing.B) and run with go test -bench=. . The framework automatically calibrates the number of iterations. // Benchmark function func BenchmarkJSONMarshal(b * testing.B) { user := Us...
36. How do you embed static files into a Go binary using go:embed?
//go:embed (Go 1.16) embeds files and directories into the compiled binary at build time. This eliminates the need to distribute static assets separately — the binary is fully self-contained. import "embed" // Embed a single file as a string // go:embed VERSION var version string // Embed a singl...
37. How do you implement timeouts for non-HTTP operations like database queries and external calls?
Context-based timeouts apply to any blocking operation — database queries, cache lookups, file operations, and external gRPC calls. The pattern is identical: create a child context with a deadline and pass it to every blocking call. // Database query with timeout func getUserFromDB(ctx context.Co...
38. What are the conventions for returning structured error responses from a Go REST API?
A consistent error response format makes APIs predictable for clients. The RFC 7807 (Problem Details for HTTP APIs) standard provides a widely adopted structure. Go implementations typically define a consistent JSON error envelope. // RFC 7807-inspired error envelope type ProblemDetail struct { T...
39. How do you implement pagination for list endpoints in a Go REST API?
Two common pagination strategies: offset-based (page/limit) and cursor-based (token-based). Cursor pagination scales better for large datasets and handles real-time data insertion without the duplicate/skip problems of offset pagination. // Offset-based pagination (simple, common for small datase...
40. How do you implement JWT authentication middleware in Go?
JWT (JSON Web Token) authentication middleware validates the token on every request, extracts claims, and attaches them to the request context for use by downstream handlers. import "github.com/golang-jwt/jwt/v5" type Claims struct { UserID int ` json: "user_id" ` Role string ` json: "role" ` jwt...
41. How do you implement HTTP response caching in a Go service?
HTTP caching reduces load and improves response times. Go services implement caching at multiple levels: HTTP Cache-Control headers (browser/CDN caching), application-level caching (Redis/in-memory), and conditional requests (ETag/Last-Modified). // HTTP Cache-Control headers func publicDataHandl...
42. How does gRPC work in Go and when would you choose it over REST/JSON?
gRPC is a high-performance RPC framework using Protocol Buffers (binary serialisation) over HTTP/2. Go has first-class gRPC support through google.golang.org/grpc . It is the standard for inter-service communication in Go microservices. // user.proto defines the service contract // service UserSe...
43. What linters and static analysis tools are essential for production Go code quality?
Go has excellent static analysis tooling built into the ecosystem. Combining multiple linters via golangci-lint catches common bugs, style violations, and security issues before code review. Key Go Linters and Tools Tool Purpose go vet Built-in: detects suspicious code (Printf format mismatches, ...
44. What is the recommended project structure for a production Go service?
Go does not mandate a project layout, but the community has converged on a practical structure that separates concerns without over-engineering. The key principle: packages should be named for what they contain, not what they do. myservice / âââ cmd / â âââ server / â âââ ma...
45. How do you implement load shedding and request queue limits in a Go HTTP server?
Load shedding protects a service from cascading failure under overload: when the system cannot keep up, it deliberately rejects additional requests rather than slowing down and failing all requests. Go implements this through semaphores and queue limits on the HTTP layer. // Concurrency limiter: ...
46. How do you correctly propagate errors from concurrent goroutines in a Go service?
When multiple goroutines run in parallel, errors must be collected and propagated without data races or goroutine leaks. The idiomatic tools are errgroup for structured concurrency and buffered channels for ad-hoc patterns. import "golang.org/x/sync/errgroup" // Pattern 1 : errgroup â run N tas...
47. How do you document a Go REST API and maintain an OpenAPI specification?
Documentation is a first-class concern for production APIs. Go projects adopt either code-first (generate OpenAPI from code annotations) or design-first (write OpenAPI spec, generate server stubs) approaches. // Approach 1: code-first with swaggo/swag annotations // go install github.com/swaggo/s...
48. What is the production readiness checklist for a Go HTTP service?
This summary covers the essential checks interviewers probe when asking 'is this service production-ready?' It combines all the topics from this set into a concise reference. Production Readiness Checklist Category Requirement Error handling All errors wrapped with %w; errors.Is/As used for inspe...