Keep Traveling

What Is Middleware in a Go Web Application?

 

What Is Middleware in a Go Web Application?

In Go’s built-in net/http package, middleware is a function that:

  • Wraps your main handler

  • Runs before the actual handler

  • Optionally runs after the handler

  • Adds cross-cutting features (logging, auth, tracing, monitoring)

Middleware is basically:

A function that intercepts an HTTP request before it reaches your handler.

Just like layers of an onion:

Client → Middleware → Handler → Response

⭐ Common Middleware Examples

  • Logging incoming requests

  • Authentication & authorization

  • Request validation

  • Setting headers

  • Rate limiting

  • Panic recovery

  • CORS handling

  • Request tracing (OpenTelemetry)


1️⃣ Text-Based Diagram: How Middleware Works

┌──────────────────────────┐ │ Client │ └───────────────▲──────────┘ │ request ▼ ┌───────────────────┐ │ Middleware │ ← logs, checks, sets headers └───────▲───────────┘ │ calls next() ▼ ┌─────────────────────┐ │ Handler │ ← business logic └─────────▲───────────┘ │ response ▼ ┌──────────────────────────┐ │ Client │ └──────────────────────────┘

2️⃣ Full Working Example: Go HTTP Server + Middleware + Handler + Resolver

We will build:

  • main.go → main entry

  • middleware.go → middleware

  • resolver.go → business resolver

  • handler.go → handler (controller)

  • Dockerfile → run as a container


📁 Folder Structure

go-middleware-demo/ │ ├── main.go ├── handler.go ├── resolver.go ├── middleware.go └── Dockerfile

3️⃣ Code: middleware.go

package main import ( "log" "net/http" "time" ) // LoggingMiddleware logs each incoming request. func LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // BEFORE handler log.Printf("Incoming request → %s %s", r.Method, r.URL.Path) // Call next handler next.ServeHTTP(w, r) // AFTER handler log.Printf("Completed → %s %s (%v)", r.Method, r.URL.Path, time.Since(start)) }) }

4️⃣ Code: resolver.go (business logic layer)

package main // Resolver simulates fetching data or doing business logic. type Resolver struct{} func (r *Resolver) GetGreeting(name string) string { if name == "" { name = "Guest" } return "Hello, " + name + "! Welcome to Go Middleware Demo." }

5️⃣ Code: handler.go (HTTP handler)

package main import ( "encoding/json" "net/http" ) type Handler struct { Resolver *Resolver } func (h *Handler) GreetingHandler(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") message := h.Resolver.GetGreeting(name) resp := map[string]string{ "message": message, } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) }

6️⃣ Code: main.go (server setup)

package main import ( "log" "net/http" ) func main() { resolver := &Resolver{} handler := &Handler{Resolver: resolver} mux := http.NewServeMux() mux.Handle("/greet", LoggingMiddleware(http.HandlerFunc(handler.GreetingHandler))) log.Println("Server started on port 8080") err := http.ListenAndServe(":8080", mux) if err != nil { log.Fatal(err) } }

7️⃣ Test the Server Locally

Run the app:

go run .

Test using browser or curl:

http://localhost:8080/greet?name=Vinod

Output:

{ "message": "Hello, Vinod! Welcome to Go Middleware Demo." }

Logs:

Incoming request → GET /greet Completed → GET /greet (1.2ms)

8️⃣ Add Docker Support (Dockerfile)

Create Dockerfile:

FROM golang:1.22-alpine AS build WORKDIR /app COPY . . RUN go mod init go-middleware-demo || true RUN go mod tidy RUN go build -o server . FROM alpine:3.19 WORKDIR /app COPY --from=build /app/server . EXPOSE 8080 CMD ["./server"]

9️⃣ Build & Run the Docker Container

Build:

docker build -t go-middleware-demo .

Run:

docker run -p 8080:8080 go-middleware-demo

Test:

http://localhost:8080/greet?name=Vinod

🔟 Text Diagram: Overall Architecture

┌────────────┐ │ Client │ └──────▲──────┘ │ ▼ ┌──────────────────────┐ │ Middleware │ │ - logging │ │ - authentication │ │ - rate limiting │ └─────────▲────────────┘ │ ▼ ┌──────────────────────┐ │ Handler │ │ - HTTP controller │ │ - calls resolver │ └─────────▲────────────┘ │ ▼ ┌──────────────────────┐ │ Resolver │ │ - business logic │ └──────────────────────┘

📝 Source code

https://github.com/kkvinodkumaran/go-middleware-demo 

 

📝 Summary (Interview-Ready)

✔ What is middleware in Go?

A function that wraps your handler to execute logic before/after request processing.

✔ What can middleware do?

  • Logging

  • Auth

  • Rate limiting

  • Setting headers

  • Error handling

  • Tracing

✔ Our example includes:

  • Logging middleware

  • Handler

  • Resolver

  • HTTP server

  • Dockerfile

     

      

Go Programming Style — Is Go OOP or Procedural? What Frameworks Does It Use?

 

Go Programming Style — Is Go OOP or Procedural? What Frameworks Does It Use?

Go (Golang) is a modern, fast, statically typed language created by Google.
But new developers often ask:

  • What kind of programming language is Go?

  • Is Go object-oriented?

  • Is Go procedural?

  • Does Go have classes?

  • What frameworks are popular in Go?

This blog explains Go’s design philosophy clearly.


1️⃣ What Is the Programming Style of Go?

Go is a multi-paradigm language with influences from:

  • Procedural programming (like C)

  • Object-oriented programming (like Java)

  • Functional programming (partial features)

  • Concurrency-first programming (goroutines & channels)

But Go does not fully belong to any one category.

The best description is:

Go is a procedural language with lightweight object-oriented features and built-in concurrency.

Let’s break this down.


2️⃣ Is Go Object-Oriented?

✔ Yes and No.

Go does not have:

❌ Classes
❌ Inheritance
❌ Constructors
❌ Overloading
❌ Traditional OOP hierarchy

But Go does have:

✔ Structs
✔ Methods on structs
✔ Encapsulation (exported/unexported)
✔ Interfaces (implicit!)
✔ Composition instead of inheritance

So Go supports object-oriented design, but without the heavy OOP complexity found in Java/C++.

Example: Methods on Struct (OOP-style)

type User struct { Name string } func (u User) Greet() string { return "Hello, " + u.Name }

Key Difference:

  • Go has no class keyword

  • Methods belong to structs implicitly

  • Interfaces are satisfied automatically (no implements keyword)

Go’s OOP philosophy:

Composition over inheritance
Interfaces over abstract classes

This makes Go simpler and more flexible.


3️⃣ Is Go Procedural?

✔ Yes, Go is strongly procedural.

Go supports:

✔ Top-level functions
✔ Packages as modules
✔ Simple flow control (if, for, switch)
✔ Straightforward function calls
✔ No hidden magic

Example:

func add(a, b int) int { return a + b }

This procedural nature keeps Go code readable and predictable.


4️⃣ Is Go Functional?

Go includes some functional features:

✔ First-class functions
✔ Passing functions as parameters
✔ Returning functions
✔ Lambdas/anonymous functions

Example:

fn := func(x int) int { return x * 2 } result := fn(5)

But Go is not a full functional language — no immutability guarantees, no pattern matching.


5️⃣ Go’s Unique Strength: Concurrency-First Design

One of Go’s main programming styles is built-in concurrency:

  • Goroutines (lightweight threads)

  • Channels (communication mechanism)

  • Select statements

Example:

go func() { fmt.Println("Hello from goroutine") }()

This is what makes Go ideal for cloud systems, servers, distributed systems, and microservices.


📝 Summary: What Style Is Go?

FeatureGo SupportNotes
Procedural✔ YesVery strong
Object-Oriented✔ PartiallyNo classes; uses structs + methods
Functional✔ PartiallyFunctions are first-class
Concurrent✔ NativeGoroutines, channels
Generic✔ Yes (Go 1.18+)Adds type safety

Go = procedural + composition-based OOP + native concurrency


6️⃣ Top Frameworks & Libraries in Golang

Go has a rich ecosystem. Here are the most popular frameworks used across the industry.


1. Web Frameworks

Gin (Most Popular)

Fast, lightweight, great for REST APIs.
https://github.com/gin-gonic/gin

Fiber

Express.js-style, extremely fast.
https://github.com/gofiber/fiber

Echo

Minimal, fast, clean.
https://github.com/labstack/echo

Chi

Idiomatic, lightweight, flexible.
https://github.com/go-chi/chi

Beego

Full-featured MVC framework.
https://github.com/beego/beego


2. Microservices Frameworks

Go-Kit

Enterprise microservice toolkit (Netflix-style).
https://github.com/go-kit/kit

Go-Micro

Tools for service discovery, RPC, configuration.
https://github.com/asim/go-micro

Kratos (Bilibili)

For large distributed systems.
https://github.com/go-kratos/kratos


3. RPC / gRPC Frameworks

gRPC (official)

High-performance RPC with protobuf.
https://github.com/grpc/grpc-go

Connect RPC

Simpler alternative to gRPC.
https://github.com/connectrpc/connect-go


4. Database Libraries

GORM

Most popular ORM for Go.
https://gorm.io/

SQLX

A thin wrapper over database/sql.
https://github.com/jmoiron/sqlx

Ent (Facebook)

Schema-based ORM with code generation.
https://entgo.io/


5. Concurrent / Distributed Systems Libraries

Go-Redis

High-performance Redis client.

NATS

Messaging system for microservices.

Kafka clients

Sarama, Confluent-Kafka-Go, Segmentio.


6. Testing Frameworks

Testify

Most popular testing framework.

Ginkgo + Gomega

BDD-style testing.


Summary (Interview-Ready)

✔ What is Go’s programming style?

Go is a procedural language with lightweight OOP features and built-in concurrency.

✔ Is Go object-oriented?

Yes, but without classes or inheritance.
Go uses structs + methods + interfaces.

✔ Is Go procedural?

Yes, strongly procedural.

✔ Is Go functional?

Partially.

✔ Top frameworks in Go?

  • Web: Gin, Fiber, Echo, Chi, Beego

  • Microservices: Go-Kit, Go-Micro, Kratos

  • RPC: gRPC, Connect RPC

  • ORM: GORM, SQLX, Ent

Go (Golang) Basics — Files, Commands, go.mod, go.sum, go tidy, vendor, download, Compilation & Testing

 

Go (Golang) Basics — Files, Commands, go.mod, go.sum, go tidy, vendor, download, Compilation & Testing

A complete beginner-friendly guide

Go is a fast, simple, and powerful language created by Google for building server-side, cloud-native, and distributed systems.

This guide gives a full beginner overview of:

✔ Go project structure
✔ Go files and packages
✔ How to run & compile Go programs
✔ How testing works
✔ What go.mod & go.sum are
✔ go mod commands: tidy, vendor, download
✔ Important Go CLI commands


Go Project Structure

A typical small Go project looks like this:

myproject/ │ ├── go.mod ├── go.sum ├── main.go └── utils/ └── math.go

Understanding Go Files

➤ A .go file contains Go code

Every file starts with a package declaration.

Example main.go:

package main import "fmt" func main() { fmt.Println("Hello, Go!") }

If a file has package main and func main() → it creates an executable program.


Go Packages

A package is simply a folder containing .go files that share the same package name.

Example:

utils/ math.go

math.go:

package utils func Add(a, b int) int { return a + b }

Import in main:

import "myproject/utils"

Go Modules (go.mod)

Modules are Go’s dependency & versioning system.

Create a module using:

go mod init myproject

This generates:

module myproject go 1.22

go.mod contains:

  • Module path

  • Go version

  • Required dependencies

  • Replace rules (optional)

Example:

module github.com/vinod/myapp go 1.22 require github.com/gin-gonic/gin v1.9.1

go.sum (Dependency Checksums)

go.sum stores cryptographic checksums of all dependencies.

Purpose:

✔ Security — Ensures dependencies weren't modified
✔ Reproducible builds — Ensures same version works everywhere
✔ Integrity verification

Example:

github.com/gin-gonic/gin v1.9.1 h1:Xu.../checksum github.com/gin-gonic/gin v1.9.1/go.mod h1:Qw.../checksum

Go verifies these every time modules are downloaded.


Go Commands for Files & Executables

Run a Go program:

go run main.go

Run entire module:

go run .

Build a binary:

go build

Build with output name:

go build -o myapp

Go Tests (_test.go)

Go has a built-in testing library.

Naming rules:

  • File ends with _test.go

  • Function format: TestXxx(t *testing.T)

Example:

func TestAdd(t *testing.T) { got := Add(2, 3) want := 5 if got != want { t.Errorf("got %d, want %d", got, want) } }

Run tests:

go test ./...

Verbose:

go test -v

Important go.mod Commands

(These are essential for real projects)


✔ go mod tidy

Cleans & fixes dependencies.

Does:

  • Add missing dependencies based on imports

  • Remove unused dependencies

  • Update go.sum

  • Keep your module graph correct

Command:

go mod tidy

Use it after:

  • Adding imports

  • Removing imports

  • Before committing code


✔ go mod vendor

Creates a vendor/ folder with copies of all dependencies.

vendor/ ├── github.com/pkg/errors/ ├── golang.org/x/net/

Purpose:

✔ Offline builds
✔ Reproducible CI builds
✔ Enterprise environments with blocked internet

Command:

go mod vendor

To compile using vendor folder:

go build -mod=vendor

✔ go mod download

Downloads all dependencies into Go’s module cache:

$GOPATH/pkg/mod

Command:

go mod download

Use cases:

  • For CI/CD systems

  • For Docker builds

  • For warming cache

  • When preparing offline builds

You can download specific modules:

go mod download github.com/gin-gonic/gin

✔ go mod verify

Verifies checksums in go.sum.

go mod verify

Ensures no dependency code was tampered with.


go get (Add/Upgrade Dependencies)

Add new dependency:

go get github.com/pkg/errors

Upgrade dependency:

go get -u github.com/pkg/errors

Remove dependency (indirectly):

go mod tidy

Go Build Modes

Cross-compile for Linux:

GOOS=linux GOARCH=amd64 go build

Cross-compile for macOS ARM:

GOOS=darwin GOARCH=arm64 go build

Cross-compile for Windows:

GOOS=windows GOARCH=amd64 go build -o app.exe

Go supports cross-compilation without extra tools.


Summary Table

Feature / CommandPurpose
go.modLists module name + dependencies
go.sumStores dependency checksums
go runBuild + run app
go buildCompile binary
go testRun tests
go mod tidyAdd missing + remove unused deps
go mod vendorCopy dependencies into vendor/
go mod downloadDownload all required deps
go fmtFormat code
go getAdd/upgrade dependency

Final Text Diagram: Go Project Workflow

Write Go code (.go files) │ ▼ Initialize module go mod init │ ▼ Add imports → dependencies appear in go.mod │ ▼ Clean module go mod tidy │ ▼ Download deps go mod download │ ▼ (Optional) create vendor folder go mod vendor │ ▼ Build or run go build go run │ ▼ Write tests → go test

How JVM Identifies and Communicates Between Stack, Heap, and Method Area

 

How JVM Identifies and Communicates Between Stack, Heap, and Method Area

Java has three types of memory involved during execution:

1️⃣ Method Area

Stores class-level metadata
(Static variables, class names, method definitions, constant pool)

2️⃣ Java Stack

Stores method frames and local variables
(Primitives + references)

3️⃣ Heap

Stores objects, arrays, Strings

The key question:

👉 How does the JVM connect these separate memory areas?

Let’s break it down step-by-step.


1. The Key to Everything: References

Java does not store objects inside the Stack.
The Stack only stores a reference (like a pointer) pointing to the object in the Heap.

Example:

Product p = new Product();

JVM Memory View:

Java Stack: p ---> #A13F22 (reference) Heap: Object Product { ... } at #A13F22

✔ p does not contain the object itself
✔ It contains an identifier (reference address)
✔ JVM uses that reference to locate the object inside the Heap


2. What is a “Reference Address”?

It is not the real OS memory address.
Java hides OS addresses for safety.

Instead, the JVM uses:

  • Object handles

  • Internal pointers

  • Indirection tables

  • Metadata tables

Depending on HotSpot implementation, objects are tracked either by:

Direct Pointer: reference → object in heap

or

Handle Table: reference → handle → object in heap

Either way:

A reference uniquely identifies and locates the object in the Heap.


3. How Stack Talks to Heap (Using References)

Example:

int x = 10; Product p = new Product(); p.name = "iPhone";

Java Stack:

Frame(main): x = 10 (primitive) p = #A13F22 (reference)

Heap:

#A13F22 → Product object { name → "iPhone" }

Flow

  1. JVM looks inside Stack

  2. Reads p

  3. Finds reference #A13F22

  4. Goes into Heap to fetch object

  5. Finds field name

  6. Accesses string "iPhone"

This is how the Stack communicates with the Heap.


4. How Heap Communicates with Method Area

When creating an object:

Product p = new Product();

JVM first checks Method Area:

Is class Product loaded?

If NOT:

  • Class Loader loads Product.class

  • Method Area stores:

    • Field names

    • Method names

    • Method bytecode

    • Constant pool

    • Static variables

Only after this:

JVM creates an object → places it in Heap.

So each object in heap points back to its class data in Method Area.

Heap object ----> Class metadata in Method Area

This is how the Heap communicates with Method Area.


5. What Identifiers Does the JVM Use?

There are three major identifiers:


1️⃣ Local Variable Identifier (Stack)

Used for:

  • Primitive values (int x)

  • References to heap (Product p)

Stack variables are identified by:

  • Name (x, p)

  • Slot number inside the frame


2️⃣ Object Reference Identifier (Heap)

Each object gets a unique reference (like an internal pointer):

#A13F22 #EF2233 #9C8821

This internal ID is what connects Stack → Heap.


3️⃣ Class Identifier (Method Area)

For each class:

  • Fully Qualified Name: com.example.Product

  • ClassLoader identity

  • Version information

Objects in Heap store a link to their class in Method Area.


6. End-to-End Communication Diagram

┌─────────────┐ │ Java Stack │ │ p = #A13F22│ └──────┬──────┘ │ (reference ID) ▼ ┌───────────────┐ │ Heap │ │ #A13F22 │ │ Product obj │ └──────┬─────────┘ │ (class pointer) ▼ ┌──────────────────────┐ │ Method Area │ │ Class Product {} │ └──────────────────────┘

This is the full path:

Stack variable → object reference → heap object → class metadata

7. What About Static Variables?

Static variables belong in Method Area.

Accessing them:

Stack variable calls → Method Area → static value

Example:

Product.count

Heap is not involved at all.


8. What About Methods?

When you call:

p.calculatePrice()

Flow is:

  1. Stack finds reference p

  2. JVM goes to Heap object

  3. Heap object points to Method Area

  4. JVM finds method bytecode

  5. Execution Engine runs the method


9. What About Thread Communication?

Each thread has:

  • Its own Java Stack

  • Its own PC Register

  • Its own Native Method Stack

But all threads share:

  • Method Area

  • Heap

This is why threads can share data (Heap)
but not each other’s local variables (Stack).


Final Simple Summary

✔ Stack

Stores names (variable identifiers)
Stores references (IDs pointing into heap)

✔ Heap

Stores objects
Each object has an internal ID and a link to its class in Method Area

✔ Method Area

Stores class definitions and static values

✔ Communication

Stack → Heap via reference ID
Heap → Method Area via class pointer

Everything begins with references.


One-Line Explanation

The Stack stores references, the Heap stores objects, and the Method Area stores class definitions. JVM connects all three using internal identifiers and pointers.

Featured Post

Confusion Matrix + Precision/Recall (Super Simple, With Examples)

  Confusion Matrix + Precision/Recall (Super Simple, With Examples) 1) Binary Classification Setup Binary classification means the model p...

Featured Posts