In this guide, we’ll walk through how to create CORS (Cross-Origin Resource Sharing) and a health check endpoint in a Golang application using the Chi router.
Setting Up Chi and CORS Middleware
We’ll use the go-chi/chi
and go-chi/cors
packages to handle routing and CORS in our application.
Step 1: Import Required Packages
First, make sure to import the necessary packages:
import (
"fmt"
"net/http"
"log"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
AdminMiddleware "github.com/project/api/middleware"
"github.com/project/api/services"
"gorm.io/gorm"
)
Step 2: Define the CORS AllowOriginFunc
We’ll define a function to specify the allowed origins for CORS. This function also logs disallowed origins:
func AllowOriginFunc(r *http.Request, origin string) bool {
allowedOrigins := []string{"http://localhost", "https://admin-micro-qa.clorian.com"}
for _, o := range allowedOrigins {
if origin == o {
return true
}
}
// Get the client's IP address
clientIP := r.RemoteAddr
// Print the log in red color
red := "\033[31m"
reset := "\033[0m"
log.Printf("%sDisallowed origin: %s, Client IP: %s%s", red, origin, clientIP, reset)
return false
}
In this function:
- allowedOrigins: This slice contains the origins that are permitted to access the resources.
- Loop through allowed origins: The function checks if the request origin is in the list of allowed origins.
- Logging disallowed origins: If the origin is not allowed, the function logs this event using
log.Printf
.
Explanation of log.Printf
log.Printf
is a function from the Go log
package that formats according to a format specifier and writes to the standard logger.
In this code:
red
andreset
are ANSI escape codes for coloring the output in the terminal.\033[31m
sets the text color to red, and\033[0m
resets it to the default color.log.Printf
prints a formatted string that includes the disallowed origin and the client’s IP address in red color to emphasize that it is a disallowed request. The formatted string includes placeholders (%s
) which are replaced by the specified variables (origin and clientIP).
Step 3: Initialize the Router
Now we initialize the router, configure middleware, and set up CORS:
func Init(db *gorm.DB) *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.Logger)
sm := services.NewServiceManager(db)
r.Use(cors.Handler(cors.Options{
AllowOriginFunc: AllowOriginFunc,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300,
}))
r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Go!")
})
return r
}
Setting Up the Health Check Endpoint
The health check endpoint is a simple route that responds with a message indicating the service is running:
r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Go!")
})
Putting It All Together
Here’s the complete code:
import (
"fmt"
"net/http"
"log"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/cors"
AdminMiddleware "github.com/project/api/middleware"
"github.com/project/api/services"
"gorm.io/gorm"
)
func AllowOriginFunc(r *http.Request, origin string) bool {
allowedOrigins := []string{"http://localhost", "https://admin-micro-qa.clorian.com"}
for _, o := range allowedOrigins {
if origin == o {
return true
}
}
clientIP := r.RemoteAddr
red := "\033[31m"
reset := "\033[0m"
log.Printf("%sDisallowed origin: %s, Client IP: %s%s", red, origin, clientIP, reset)
return false
}
func Init(db *gorm.DB) *chi.Mux {
r := chi.NewRouter()
r.Use(middleware.Logger)
sm := services.NewServiceManager(db)
r.Use(cors.Handler(cors.Options{
AllowOriginFunc: AllowOriginFunc,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300,
}))
r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Go!")
})
return r
}
This setup ensures your Go application can handle cross-origin requests securely and provides a health check endpoint to monitor the application’s status.