Skip to content

Go Web Frameworks — Building Web Applications with Gin, Echo, and Fiber

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Go Web Frameworks. We cover key concepts, practical examples, and best practices to help you master this topic.

Go web frameworks like Gin, Echo, and Fiber provide routing, middleware, and context utilities for building high-performance web applications.

What You'll Learn

  • Gin framework routing and middleware
  • Echo framework features
  • Fiber framework (Express-like)
  • Framework comparison

Why It Matters

Web frameworks speed up development. Docker registry API uses Gin. DodaZIP uses Gin for file processing API. Many production Go services use these frameworks.

Real-World Use

REST APIs, microservices, web applications, API gateways, admin dashboards.

flowchart LR
    A["Web Frameworks"] --> B["Gin"]
    A --> C["Echo"]
    A --> D["Fiber"]
    B --> E["Routing"]
    B --> F["Middleware"]
    A:::current --> B
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
    style F fill:#f1f5f9,stroke:#94a3b8,color:#64748b

Gin Framework

func main() {
    r := gin.Default()

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"message": "pong"})
    })

    api := r.Group("/api")
    {
        api.GET("/users", listUsers)
        api.POST("/users", createUser)
        api.GET("/users/:id", getUser)
        api.PUT("/users/:id", updateUser)
        api.DELETE("/users/:id", deleteUser)
    }

    r.Run(":8080")
}

func listUsers(c *gin.Context) {
    var users []User
    db.Find(&users)
    c.JSON(http.StatusOK, users)
}

Echo Framework

func main() {
    e := echo.New()
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
    })

    e.POST("/users", func(c echo.Context) error {
        u := new(User)
        if err := c.Bind(u); err != nil {
            return err
        }
        return c.JSON(http.StatusCreated, u)
    })

    e.Logger.Fatal(e.Start(":8080"))
}

Fiber Framework

func main() {
    app := fiber.New()

    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Hello, World!")
    })

    app.Get("/user/:name", func(c *fiber.Ctx) error {
        name := c.Params("name")
        return c.JSON(fiber.Map{"name": name})
    })

    app.Post("/upload", func(c *fiber.Ctx) error {
        file, _ := c.FormFile("document")
        return c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
    })

    app.Listen(":8080")
}

Middleware

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
            return
        }
        c.Set("user_id", "user-123")
        c.Next()
    }
}

func CORSMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "*")
        c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(http.StatusNoContent)
            return
        }
        c.Next()
    }
}

Framework Comparison

Feature Gin Echo Fiber
Router Radix tree Radix tree Radix tree
Performance Fast Fast Fastest
Middleware Rich ecosystem Built-in Express-like
Learning Curve Moderate Easy Easy (Express devs)
Community Largest Large Growing

Common Mistakes

1. Not Using Bindings

Use c.ShouldBindJSON, c.Bind, c.Validate for request parsing. Avoid manual JSON decoding.

2. Ignoring Request Validation

Use binding tags: json:"name" binding:"required". Gin validates automatically.

3. Blocking in Handlers

Long operations should use goroutines. Return 202 Accepted for async processing.

4. Not Handling Panics

Use recovery middleware. Gin has gin.Recovery() built-in.

5. Missing Request Timeouts

Use context timeouts for database and external API calls.

Practice Questions

1. What are the key features of Gin? Fast routing with radix tree, middleware chaining, JSON binding/validation, error management.

2. How do you handle file uploads in Fiber? c.FormFile("field") returns file header. c.SaveFile(file, path) saves to disk.

3. What is middleware in reverse proxy? Functions that execute before/after handlers. Used for logging, auth, CORS, Rate Limiting.

4. How do you group routes? Use RouterGroup: r.Group("/api/v1"). All routes in group share prefix and middleware.

Challenge: Build a Gin API that serves JSON from a PostgreSQL database.

Solution
func main() {
    db := connectDB()
    r := gin.Default()

    r.GET("/products", func(c *gin.Context) {
        var products []Product
        db.Find(&products)
        c.JSON(200, products)
    })

    r.GET("/products/:id", func(c *gin.Context) {
        var product Product
        if err := db.First(&product, c.Param("id")).Error; err != nil {
            c.JSON(404, gin.H{"error": "not found"})
            return
        }
        c.JSON(200, product)
    })

    r.Run(":8080")
}

FAQ

{{< faq question="Which framework should I use?" >}} Gin for most projects (largest community). Fiber for maximum performance. Echo if you want built-in middleware. Chi for minimalism. {{< /faq >}}

{{< faq question="Can I use net/http with these frameworks?" >}} Yes. All frameworks support http.Handler interface. You can mix standard handlers with framework handlers. {{< /faq >}}

{{< faq question="How do I serve static files?" >}} Gin: r.Static("/static", "./public"). Echo: e.Static("/static", "public"). Fiber: app.Static("/static", "./public"). {{< /faq >}}

{{< faq question="What is the performance difference?" >}} Fiber is fastest (fiber-based). Gin and Echo are comparable. All are fast enough for most applications. Profile before optimizing. {{< /faq >}}

{{< faq question="How do I handle WebSockets?" >}} Gin has gin-gonic/contrib/Websocket. Echo has e.WebSocket. Fiber has app.Get("/ws", websocket.New(func(c *websocket.Conn) {})). {{< /faq >}}

Try It Yourself

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "Hello, World!"})
    })
    r.Run(":8080")
}

Expected output — Gin server running on :8080, respond to GET /hello with JSON.

What's Next

Now that you understand web frameworks, explore middleware patterns in depth.

Topic Description Link
Go Middleware HTTP middleware {{< ref "41-middleware" >}}
Go Testing HTTP Testing HTTP handlers {{< ref "42-testing-http" >}}
Go Deployment Deploying Go apps {{< ref "43-deployment" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro

Home Browse Go