Gin
Gin (https://gin-gonic.com/) is an HTTP Web framework written in the Go programming language. It features an API similar to Martini's but performs 40 times faster. Gin utilizes a custom version of HttpRouter, therefore it 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 sample source code, see: cloudrun-gin
Prerequisites
Before you begin, ensure that you have:
- Installed Go 1.23 or a later version
- Have a Tencent Cloud account and have activated the CloudBase service
- Have a basic knowledge of the Go programming language and the Gin framework development
Step 1: Create a Gin Application
💡 Note: If you already have a Gin application, you can skip this step.
Create the 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, supporting environment variables
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Start up the server
router.Run(":" + port)
}
Test the application locally
Start up the application:
go run main.go
Open your browser and visit http://localhost:8080, you should see a JSON response.
Step 2: Add API routes
Let's create a RESTful API to demonstrate the features of Gin.
Create User Model
Create the models directory in the project root directory and create the user.go file:
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 User Controller
Create the controllers directory in the project root directory and create the 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: "Obtained successfully",
Data: gin.H{
"total": len(users),
"page": page,
"limit": limit,
"items": paginatedUsers,
},
})
}
// GetUser Obtains 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: "Obtained successfully",
Data: user,
})
return
}
}
c.JSON(http.StatusNotFound, models.ApiResponse{
Success: false,
Message: "User does not exist",
})
}
// CreateUser Creates 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,
Message: "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 router 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, supporting environment variables
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Start up the server
router.Run(":" + port)
}
Step 3: Local Testing
Update dependencies
go mod tidy
Starting Up the Application
go run main.go
Testing API Endpoints
# Test Health Check
curl http://localhost:8080/health
# Test Homepage
curl http://localhost:8080/
# Test User List
curl http://localhost:8080/api/users
# Test Pagination
curl "http://localhost:8080/api/users?page=1&limit=2"
# Test Obtaining a Single User
curl http://localhost:8080/api/users/1
# Test 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 the Startup Script
💡 Note:
- When creating the
scf_bootstrapfile on windows, it is recommended to use- When creating the
scf_bootstrapfile using vscode on windows, deploying to an HTTP cloud function may result in an error:scf_bootstrapfile does not exist- This error occurs because the script file contains Windows-style carriage returns (^M), causing Linux to fail to recognize the interpreter path correctly. This is a common issue in WSL
Create the scf_bootstrap file (with no extension):
#!/bin/bash
export PORT=9000
export GIN_MODE=release
./main
Grant execute permissions 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- Compile the Go application into a Linux binary
- 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
Deploy via the console
- Log in to the CloudBase console
- Select your environment and go to the cloud function page
- Click "New Cloud Function"
- Select "HTTP cloud function"
- Fill in the function name (such as:
gin-app) - Select runtime: Go 1.x (or other supported versions)
- Select submit method: Local code package upload
- Upload the compiled binary files 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 you need to package manually:
# Compile the Application
GOOS=linux GOARCH=amd64 go build -o main .
# Create 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 custom domain access to 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 the HTTP cloud function 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 via the environment variable PORT=9000, and uses port 8080 by default during local development.
Q: How to perform cross-compilation for 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 performing duplicate initialization operations during startup
- Configure memory appropriately
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 start up the compiled binary file.
Next steps
- Learn more about HTTP cloud function configuration options
- Learn how to connect to CloudBase database