Go Lang Basics Part 2
Part 2 Building REST APIs with Fiber in Go: A Detailed Guide with JWT Authentication
Prerequisites:
- Basic understanding of Go programming
- Familiarity with HTTP concepts
Step 1: Project Setup
- Open your terminal or command prompt.
- Create a project directory:
mkdir go-fiber-api cd go-fiber-api
- Initialize a Go module:
go mod init github.com/your-username/go-fiber-api
- Replace
github.com/your-username/go-fiber-api
with the appropriate module path for your project.
- Replace
Step 2: Folder Structure
Create these subfolders inside go-fiber-api
:
controllers
models
middleware
utils
Step 3: Install Dependencies
go get -u github.com/gofiber/fiber/v2
- Install other dependencies as needed (database drivers, JWT library, etc.)
Step 4: Models (models/product.go
)
package models
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
}
Step 5: Controllers (controllers/products.go
)
package controllers
import (
"fmt"
"github.com/gofiber/fiber/v2"
"go-fiber-api/models"
)
// In-memory product data (replace with database later)
var products []models.Product = []models.Product{
{ID: 1, Name: "T-Shirt", Price: 19.99},
{ID: 2, Name: "Coffee Mug", Price: 9.99},
}
// GetProducts fetches all products
func GetProducts(c *fiber.Ctx) error {
return c.JSON(products)
}
// GetProductByID fetches a product by ID
func GetProductByID(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
if err != nil {
return c.Status(400).SendString("Invalid product ID")
}
for _, product := range products {
if product.ID == id {
return c.JSON(product)
}
}
return c.Status(404).SendString("Product not found")
}
Step 6: Routing (main.go
)
package main
import (
"github.com/gofiber/fiber/v2"
"go-fiber-api/controllers"
)
func main() {
app := fiber.New()
api := app.Group("/api")
api.Get("/products", controllers.GetProducts)
api.Get("/products/:id", controllers.GetProductByID)
app.Listen(":3000")
}
Step 7: Run the Application
go run main.go
Test by visiting http://localhost:3000/api/products
in your browser.
Part 3 JWT Authentication
- Install the JWT library:
go get -u github.com/golang-jwt/jwt/v4
- Create an authentication middleware function (
middleware/auth.go
)
package middleware
import (
"fmt"
"github.com/dgrijalva/jwt-go/v4"
"github.com/gofiber/fiber/v2"
)
// Change this to a secure secret key
var jwtSecret = []byte("your_strong_secret_key")
// Authenticate middleware checks for a valid JWT
func Authenticate(c *fiber.Ctx) error {
tokenString := c.Get("Authorization")
tokenString = strings.Replace(tokenString, "Bearer ", "", 1) // Remove 'Bearer' prefix
// Parse the JWT token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Ensure signing method matches expected
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// Return the secret key for validation
return jwtSecret, nil
})
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"message": "Invalid or expired token",
})
}
// Extract user data from token (requires defining claims)
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"message": "Invalid token",
})
}
// Set user data in request context for later access
c.Locals("userId", claims["userId"]) // Example, adjust as necessary
return c.Next()
}
3. Generate JWTs During Login (Example - Simplify as needed)
// ... (in your login controller )
// Simulate successful login
userId := 1 // Replace with actual login logic
// Create JWT claims (add more user data if needed)
claims := jwt.MapClaims{
"userId": userId,
"exp": time.Now().Add(time.Hour * 24).Unix(), // Example 24-hour expiration
}
// Generate token with HMAC-SHA256 signing method
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtSecret)
if err != nil {
// Handle error
}
// Return the generated token to the client
return c.JSON(fiber.Map{
"token": tokenString,
})
4. Protect Routes (main.go
)
// ... in your main file ...
app.Use("/api/protected", Authenticate) // Apply middleware to group or specific routes
api.Get("/protected/data", func(c *fiber.Ctx) error {
userId := c.Locals("userId") // Access authenticated user's ID
return c.JSON(fiber.Map{
"message": "Access granted!",
"userId": userId,
})
})
Explanation
Authenticate
Middleware:- Extracts the JWT from the
Authorization
header. - Verifies the token's signature and validity.
- Extracts user data from the JWT claims (you'll need to define appropriate claim fields).
- Extracts the JWT from the
- Login Example:
- Replace with your authentication logic.
- Creates JWT claims containing user info and expiration.
- Signs the token with your secret key.
- Protected Route:
- The middleware ensures only requests with valid JWTs can access protected routes.
Important:
- Secure Secret Key: Use a strong, unpredictable secret key and store it securely.
- Error Handling: Implement robust error handling.
- Custom Claims: Design JWT claims to hold necessary user information for your application.