Gin

Main

  • To initialize the server when run on specific port

package main

import (
	"golang-playground/controller"
	"log"

	"os"
	"os/signal"
	"syscall"

	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		log.Println("Error loading .env file")
	}
	controller := controller.NewInternalController()
	// open the new thread to run the server instead of blocking the main thread
	go func() {
		if err := controller.Run("8080"); err != nil {
			log.Fatalf("Failed to start server: %v", err)
		}
	}()
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
}

Controller

  • To declare each api end point and applied middleware

package controller

import (
	"golang-playground/middleware"
	"golang-playground/service"
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

type InternalController struct {
	router *gin.Engine
}

type TestBody struct {
	// name can be nullable, if not provided, the default value is empty string
	Name   *string `json:"name"`
	Action string  `json:"action" binding:"required"`
}

func NewInternalController() *InternalController {
	r := gin.Default()
	corsConfig := cors.DefaultConfig()

	r.SetTrustedProxies([]string{"127.0.0.1", "::1"})
	corsConfig.AllowOrigins = []string{"http://localhost:5000", "http://localhost:5006"}
	// Configure CORS
	corsConfig.AllowMethods = []string{"POST", "GET", "PUT", "OPTIONS"}
	corsConfig.AllowHeaders = []string{"Origin", "Content-Type", "Authorization", "X-CSRF-Token"}
	corsConfig.ExposeHeaders = []string{"Content-Length", "X-CSRF-Token"}
	corsConfig.AllowCredentials = true
	corsConfig.MaxAge = 12 * time.Hour
	// apply cors as middleware
	r.Use(cors.New(corsConfig))
	internalService := service.NewInternalService()
	internalMiddleware := middleware.NewInternalMiddleware()
	// separate the routes
	app := r.Group("/app")
	// apply internal middleware
	app.Use(internalMiddleware.SubscriptionKeyMiddleware())
	{
		app.GET("/items", func(c *gin.Context) {
			items := internalService.GetItems()
			c.JSON(200, items)
		})
	}
	r.GET("/test/:name", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Query("action")
		c.JSON(200, gin.H{
			"name":   name,
			"action": action,
		})
	})
	r.POST("/test", func(c *gin.Context) {
		var testBody TestBody
		// body json validation
		if err := c.ShouldBindJSON(&testBody); err != nil {
			c.JSON(400, gin.H{
				"error": err.Error(),
			})
			return
		}
		c.JSON(200, testBody)
	})
	return &InternalController{
		router: r,
	}
}

func (s *InternalController) Run(port string) error {
	return s.router.Run(":" + port)
}

Middleware

  • To declare the middleware to intercept the request before passing to the controller

package middleware

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

type InternalMiddleWare struct {
}

func NewInternalMiddleware() *InternalMiddleWare {
	return &InternalMiddleWare{}
}

// Middleware to check for x-esi-accesskey header
func (m *InternalMiddleWare) SubscriptionKeyMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		subscriptionKey := c.GetHeader("x-esi-accesskey")

		if subscriptionKey == "" {
			c.AbortWithStatus(403)
			return
		}
		c.Next()
	}
}

Service

  • The logicial layer

package service

type InternalService struct {
}

func NewInternalService() *InternalService {
	return &InternalService{}
}

func (s *InternalService) GetItems() [2]string {
	return [2]string{"Item 1", "Item 2"}
}

Last updated

Was this helpful?