Skip to main content

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_bootstrap is the startup script for CloudBase cloud functions
  • The Go application needs to be compiled into a Linux binary file
  • Set the PORT=9000 environment variable to ensure the application listens on the correct port
  • Set GIN_MODE=release to optimize performance

Step 5: Deploy to CloudBase

Deployment via the Console

  1. Log in to the CloudBase Console
  2. Select your environment and go to the cloud function page
  3. Click "Create New Cloud Function"
  4. Select "HTTP Cloud Function"
  5. Fill in the function name (e.g.: gin-app)
  6. Select runtime: Go 1.x (or other supported versions)
  7. Select submission method: Local upload of code package
  8. Upload the compiled binary file and the scf_bootstrap file
  9. Automatic dependency installation: Disable (Not required for Go applications)
  10. 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.ReleaseMode mode
  • 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