This document details how to develop functions by using Go from NHN Cloud's Cloud Functions service.
| Item | Value |
|---|---|
| Supported version | 1.22, 1.23, 1.24, 1.25 |
| File name | functions.go |
| Entry Point | Handler |
A basic form of function.
package main
import (
"fmt"
"log"
"net/http"
"github.com/brianvoe/gofakeit/v6"
)
func Handler(w http.ResponseWriter, r *http.Request) {
name := gofakeit.Name()
email := gofakeit.Email()
city := gofakeit.City()
msg := fmt.Sprintf("Fake Name: %s\nEmail: %s\nCity: %s\n", name, email, city)
_, err := w.Write([]byte(msg))
if err != nil {
log.Printf("Error writing response: %v", err)
}
}
In Go functions, HTTP requests and responses are processed via http.ResponseWriter and *http.Request.
package main
import (
"encoding/json"
"log"
"net/http"
)
func Handler(w http.ResponseWriter, r *http.Request) {
// HTTP request information
method := r.Method
headers := r.Header
query := r.URL.Query()
// Configure response data
response := map[string]interface{}{
"method": method,
"headers": headers,
"query": query,
"path": r.URL.Path,
}
// Configure JSON response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Printf("Error encoding response: %v", err)
}
}
You can download the Go template provided by Cloud Functions to develop a local environment.
Template download link: go.zip
The structure of the downloaded template file is as follows:
go.zip
├── functions.go # Main function file
└── go.mod # Dependency management file
Include basic fake data generation functions.
package main
import (
"fmt"
"log"
"net/http"
"github.com/brianvoe/gofakeit/v6"
)
func Handler(w http.ResponseWriter, r *http.Request) {
name := gofakeit.Name()
email := gofakeit.Email()
city := gofakeit.City()
msg := fmt.Sprintf("Fake Name: %s\nEmail: %s\nCity: %s\n", name, email, city)
_, err := w.Write([]byte(msg))
if err != nil {
log.Printf("Error writing response: %v", err)
}
}
module example.com/ncf
go 1.22
require github.com/brianvoe/gofakeit/v6 v6.28.0
# Unzip
unzip go.zip -d my-function
# Move to task directory
cd my-function
Modify functions.go file with the logic you want.
// functions.go - Simple modification example
package main
import (
"encoding/json"
"net/http"
"time"
)
func Handler(w http.ResponseWriter, r *http.Request) {
// Import name from query parameter
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
// Import message from body if POST request
var customMessage string
if r.Method == "POST" {
var data map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&data); err == nil {
if msg, ok := data["message"].(string); ok {
customMessage = msg
}
}
}
// Configure response data
response := map[string]interface{}{
"greeting": "Hello, " + name + "!",
"message": customMessage,
"method": r.Method,
"timestamp": time.Now().Format(time.RFC3339),
}
// JSON response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}
Compress the modified source code into ZIP file.
# Windows (PowerShell)
Compress-Archive -Path .\functions.go, .\go.mod -DestinationPath my-function.zip
# Windows (when using 7-Zip)
7z a my-function.zip functions.go go.mod
# macOS/Linux
zip my-function.zip functions.go go.mod
# Include all files (if any additional files are available)
zip -r my-function.zip . -x "*.git*" "go.sum" "test.go"
Used when uploading files from the user's local environment when creating or modifying a function. (refer to Console Guide)
.go file and go.mod must be located directly in the root of the ZIP file.Right structure:
my-function.zip
├── functions.go
├── go.mod
└── utils.go (if there are additional files)
Wrong structure:
my-function.zip
└── my-function/
├── functions.go
└── go.mod
go.sum file should not be included.# Similar to .gitignore, exclude the following files:
zip -r my-function.zip . -x \
"go.sum" \
".git/*" \
"*.log" \
"test.go" \
".env" \
"*.zip"
package main
import (
"encoding/json"
"net/http"
"time"
)
func Handler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
// Import query parameter
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
greeting := r.URL.Query().Get("greeting")
if greeting == "" {
greeting = "Hello"
}
response := map[string]interface{}{
"message": greeting + ", " + name + "!",
"timestamp": time.Now().Format(time.RFC3339),
"method": "GET",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
package main
import (
"encoding/json"
"io"
"net/http"
"time"
)
type RequestBody struct {
Name string `json:"name"`
Email string `json:"email"`
Message string `json:"message"`
}
func Handler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
return
}
// Read request body
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading body", http.StatusBadRequest)
return
}
defer r.Body.Close()
var requestBody RequestBody
err = json.Unmarshal(body, &requestBody)
if err != nil {
http.Error(w, "Invalid JSON format", http.StatusBadRequest)
return
}
// Validate required fields
if requestBody.Name == "" {
http.Error(w, "Missing required field: name", http.StatusBadRequest)
return
}
// Generate response data
response := map[string]interface{}{
"id": generateID(),
"name": requestBody.Name,
"email": getOrDefault(requestBody.Email, "not provided"),
"message": getOrDefault(requestBody.Message, "No message"),
"processed_at": time.Now().Format(time.RFC3339),
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(response)
}
func generateID() string {
// Generate simple ID (use UUID, etc. in reality)
return time.Now().Format("20060102150405")
}
func getOrDefault(value, defaultValue string) string {
if value == "" {
return defaultValue
}
return value
}
Write go.mod to manage dependencies.
module example.com/myfunction
go 1.25
require (
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
)
package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
func Handler(w http.ResponseWriter, r *http.Request) {
userID := r.URL.Query().Get("userId")
if userID == "" {
http.Error(w, "userId is required", http.StatusBadRequest)
return
}
// External API call
resp, err := http.Get(fmt.Sprintf("https://jsonplaceholder.typicode.com/users/%s", userID))
if err != nil {
http.Error(w, "External API error", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
http.Error(w, "User not found", http.StatusNotFound)
return
}
if resp.StatusCode != 200 {
http.Error(w, "External API error", http.StatusInternalServerError)
return
}
var userData map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&userData); err != nil {
http.Error(w, "Failed to parse response", http.StatusInternalServerError)
return
}
// Response configuration
response := map[string]interface{}{
"user": userData,
"fetched_at": time.Now().Format(time.RFC3339),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
package main
import (
"encoding/json"
"io"
"net/http"
"sort"
"strings"
"time"
"github.com/google/uuid"
)
type DataItem struct {
Name string `json:"name"`
}
type ProcessedItem struct {
ID string `json:"id"`
Name string `json:"name"`
ProcessedAt string `json:"processed_at"`
NormalizedName string `json:"normalized_name"`
}
func Handler(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading body", http.StatusBadRequest)
return
}
defer r.Body.Close()
var request struct {
Data []DataItem `json:"data"`
}
if err := json.Unmarshal(body, &request); err != nil {
http.Error(w, "Invalid JSON format", http.StatusBadRequest)
return
}
if request.Data == nil {
http.Error(w, "Data must be an array", http.StatusBadRequest)
return
}
// Data processing
var processedData []ProcessedItem
for _, item := range request.Data {
if item.Name != "" {
processed := ProcessedItem{
ID: uuid.New().String()[:8],
Name: item.Name,
ProcessedAt: time.Now().Format(time.RFC3339),
NormalizedName: normalizeName(item.Name),
}
processedData = append(processedData, processed)
}
}
// Data sorting
sort.Slice(processedData, func(i, j int) bool {
return processedData[i].NormalizedName < processedData[j].NormalizedName
})
// Filter only vaild data
validData := make([]ProcessedItem, 0)
for _, item := range processedData {
if item.NormalizedName != "" {
validData = append(validData, item)
}
}
response := map[string]interface{}{
"total_processed": len(processedData),
"valid_items": len(validData),
"data": validData,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
func normalizeName(name string) string {
if name == "" {
return ""
}
return strings.Title(strings.TrimSpace(name))
}
Use the function name as the Entry Point.
Function name: Handler
Entry Point: Handler
You can define multiple functions in a single file.
// handlers.go
package main
import (
"encoding/json"
"net/http"
)
func GetUser(w http.ResponseWriter, r *http.Request) {
// User lookup logic
response := map[string]string{"message": "Get user"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
func CreateUser(w http.ResponseWriter, r *http.Request) {
// User creation logic
response := map[string]string{"message": "User created"}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(response)
}
func UpdateUser(w http.ResponseWriter, r *http.Request) {
// User modification logic
response := map[string]string{"message": "User updated"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
Entry Point configuration:
- GetUser
- CreateUser
- UpdateUser
| Version | End of Support | End of Service |
|---|---|---|
| 1.25 | - | - |
| 1.24 | - | - |
| 1.23 | 2026-02-21 | 2026-08-21 |
| 1.22 | 2026-01-28 | 2026-07-28 |
Cloud Functions follows Go's official release policy. Go releases new major versions twice a year (January and July), and each version is supported only up to the latest two major versions.
Recommendation: use the latest supported version (1.24 or 1.25) to continue receiving security patches and bug fixes.