Gin
Gin is an HTTP Web framework written in Go. It boasts a Martini-like API but with performance that is 40 times faster. Gin utilizes a custom version of HttpRouter, which not only delivers extremely fast routing but also provides middleware support.
This guide describes how to deploy Gin applications on CloudBase HTTP cloud functions.
For the sample source code, see: cloudrun-gin
Prerequisites
Before you begin, ensure that you have:
- Installed Go 1.23 or later version
- Have a Tencent Cloud account with CloudBase service activated
- Have a basic understanding of Go language and Gin framework development
Step 1: Create a Gin Application
💡 Tip: If you already have a Gin application, you can skip this step.
Create a project directory
mkdir cloudrun-gin
cd cloudrun-gin
Initialize the Go module
go mod init cloudrun-gin
go get -u github.com/gin-gonic/gin
Create the Main Application File
Create the main.go file in the cloudrun-gin directory:
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
)
func main() {
// Set the Gin mode
if os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}
router := gin.Default()
// Basic routes
router.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Welcome to the Gin CloudBase application!",
"status": "running",
})
})
// Health Check
router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"framework": "Gin",
"go_version": "1.19+",
"gin_version": gin.Version,
})
})
// Get the port with environment variable support
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Start the server
router.Run(":" + port)
}
Test the Application Locally
Start up the application:
go run main.go
Open the browser and go to http://localhost:8080. You should see a JSON response.
Step 2: Add API Routes
Let's create a RESTful API to demonstrate Gin's feature.
Create the User Model
Create a models directory in the project root and a user.go file within it:
package models
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
type ApiResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
Create the User Controller
Create a controllers directory in the project root directory, and create a user.go file:
package controllers
import (
"net/http"
"strconv"
"sync"
"cloudrun-gin/models"
"github.com/gin-gonic/gin"
)
var (
users []models.User
usersMu sync.RWMutex
nextID = 1
)
func init() {
// Initialize test data
users = []models.User{
{ID: 1, Name: "Zhang San", Email: "zhangsan@example.com"},
{ID: 2, Name: "Li Si", Email: "lisi@example.com"},
{ID: 3, Name: "Wang Wu", Email: "wangwu@example.com"},
}
nextID = 4
}
// GetUsers obtains the user list
func GetUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
usersMu.RLock()
defer usersMu.RUnlock()
startIndex := (page - 1) * limit
endIndex := startIndex + limit
if startIndex >= len(users) {
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "Obtained successfully",
Data: []models.User{},
})
return
}
if endIndex > len(users) {
endIndex = len(users)
}
paginatedUsers := users[startIndex:endIndex]
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "Obtain success"
Data: gin.H{
"total": len(users),
"page": page,
"limit": limit,
"items": paginatedUsers,
},
})
}
// GetUser get the user by ID
func GetUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Message: "Invalid user ID",
})
return
}
usersMu.RLock()
defer usersMu.RUnlock()
for _, user := range users {
if user.ID == id {
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "Obtain success"
Data: user,
})
return
}
}
c.JSON(http.StatusNotFound, models.ApiResponse{
Success: false,
Message: "User not found",
})
}
// CreateUser create a user
func CreateUser(c *gin.Context) {
var newUser models.User
if err := c.ShouldBindJSON(&newUser); err != nil {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Message: "Request parameter error: " + err.Error(),
})
return
}
if newUser.Name == "" || newUser.Email == "" {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Name and email cannot be empty
})
return
}
usersMu.Lock()
newUser.ID = nextID
nextID++
users = append(users, newUser)
usersMu.Unlock()
c.JSON(http.StatusCreated, models.ApiResponse{
Success: true,
Message: "Created successfully",
Data: newUser,
})
}
Update the Main Application File
Update the main.go file to add routes and middleware:
package main
import (
"fmt"
"net/http"
"os"
"time"
"cloudrun-gin/controllers"
"github.com/gin-gonic/gin"
)
func main() {
// Set the Gin mode
if os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}
router := gin.Default()
// Add CORS middleware
router.Use(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()
})
// Add logging middleware
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
// Basic routes
router.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Welcome to the Gin CloudBase application!",
"status": "running",
})
})
// Health Check
router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"timestamp": time.Now().Format(time.RFC3339),
"framework": "Gin",
"go_version": "1.19+",
"gin_version": gin.Version,
})
})
// API routes group
api := router.Group("/api")
{
users := api.Group("/users")
{
users.GET("", controllers.GetUsers)
users.GET("/:id", controllers.GetUser)
users.POST("", controllers.CreateUser)
}
}
// Get the port with environment variable support
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Start the server
router.Run(":" + port)
}
Step 3: Local Testing
Update Dependencies
go mod tidy
Start the Application
go run main.go
Test the API Interface
# Testing Health Check
curl http://localhost:8080/health
# Home Page Testing
curl http://localhost:8080/
# Testing User List
curl http://localhost:8080/api/users
# Pagination Testing
curl "http://localhost:8080/api/users?page=1&limit=2"
# Testing Obtaining a Single User
curl http://localhost:8080/api/users/1
# Testing Creating a User
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"New User","email":"newuser@example.com"}'
Step 4: Prepare Deployment Files
1. Create Startup Script
Create the scf_bootstrap file (without an extension):
#!/bin/bash
export PORT=9000
export GIN_MODE=release
./main
Grant execute permission to the startup script:
chmod +x scf_bootstrap
2. Compile the Application
Compile the Go application into a Linux binary:
# Cross-Compile for Linux 64-bit
GOOS=linux GOARCH=amd64 go build -o main .
3. Project Structure
cloudrun-gin/
├── controllers/
│ └── user.go
├── models/
│ └── user.go
├── main.go
├── go.mod
├── go.sum
├── main # Compiled binary file
└── scf_bootstrap # 🔑 Cloud function startup script
💡 Note:
scf_bootstrapis the startup script for CloudBase cloud functions- The Go application needs to be compiled into a Linux binary file
- Set the
PORT=9000environment variable to ensure the application listens on the correct port- Set
GIN_MODE=releaseto optimize performance
Step 5: Deploy to CloudBase
Deployment via the Console
- Log in to the CloudBase Console
- Select your environment and go to the cloud function page
- Click "Create New Cloud Function"
- Select "HTTP Cloud Function"
- Fill in the function name (e.g.:
gin-app) - Select runtime: Go 1.x (or other supported versions)
- Select submission method: Local upload of code package
- Upload the compiled binary file and the
scf_bootstrapfile - Automatic dependency installation: Disable (Not required for Go applications)
- Click the "Create" button and wait for deployment to complete
Package and deploy
If manual packaging is required:
# Compile the Application
GOOS=linux GOARCH=amd64 go build -o main .
# Create the Deployment Package
zip -j gin-app.zip main scf_bootstrap
Step 6: Access Your Application
After successful deployment, you can refer to Accessing Cloud Functions via HTTP to set up a custom domain for accessing the
Example Request
# Health Check
curl https://your-app-url/health
# Obtain User List
curl https://your-app-url/api/users
# Pagination Query
curl "https://your-app-url/api/users?page=1&limit=2"
# Create New User
curl -X POST https://your-app-url/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com"}'
Frequently Asked Questions
Q: Why must HTTP cloud functions use port 9000?
A: CloudBase HTTP cloud functions require the application to listen on port 9000, which is the standard configuration of the platform. The application controls the port through the environment variable PORT=9000, while using port 8080 by default during local development.
Q: How to cross-compile Go applications?
A: Use the following command to perform cross-compilation:
GOOS=linux GOARCH=amd64 go build -o main .
Q: How to optimize the cold startup time of Go applications?
A:
- Reduce the number of dependency packages
- Use
gin.ReleaseModemode - Avoid repeated initialization operations during startup
- Properly configure memory settings
Q: What is the purpose of the scf_bootstrap file?
A: scf_bootstrap is the startup script for cloud functions, used to set environment variables and launch the compiled binary file.
Next Steps
- Learn more about HTTP Cloud Function Configuration Options
- Learn how to connect to the CloudBase database