YAML 响应

YAML 在配置文件领域很流行,有时候 API 也需要返回 YAML 格式的数据,比如配置中心、CI/CD 系统等。Gin 同样支持。

基本 YAML 响应

使用 c.YAML() 方法:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    
    r.GET("/config", func(c *gin.Context) {
        c.YAML(http.StatusOK, gin.H{
            "server": gin.H{
                "host": "0.0.0.0",
                "port": 8080,
            },
            "database": gin.H{
                "driver":   "mysql",
                "host":     "localhost",
                "port":     3306,
                "database": "myapp",
            },
            "redis": gin.H{
                "host": "localhost",
                "port": 6379,
            },
        })
    })
    
    r.Run(":8080")
}

返回结果:

database:
  database: myapp
  driver: mysql
  host: localhost
  port: 3306
redis:
  host: localhost
  port: 6379
server:
  host: 0.0.0.0
  port: 8080

使用结构体

用结构体可以让代码更清晰:

type ServerConfig struct {
    Host string `yaml:"host"`
    Port int    `yaml:"port"`
}

type DatabaseConfig struct {
    Driver   string `yaml:"driver"`
    Host     string `yaml:"host"`
    Port     int    `yaml:"port"`
    Database string `yaml:"database"`
}

type AppConfig struct {
    Server   ServerConfig   `yaml:"server"`
    Database DatabaseConfig `yaml:"database"`
}

r.GET("/app/config", func(c *gin.Context) {
    config := AppConfig{
        Server: ServerConfig{
            Host: "0.0.0.0",
            Port: 8080,
        },
        Database: DatabaseConfig{
            Driver:   "mysql",
            Host:     "localhost",
            Port:     3306,
            Database: "myapp",
        },
    }
    c.YAML(http.StatusOK, config)
})

实际应用场景

YAML 响应在一些特定场景很有用:

配置中心服务

r.GET("/configs/:app", func(c *gin.Context) {
    appName := c.Param("app")
    
    config := loadConfigFromDB(appName)
    
    c.YAML(http.StatusOK, config)
})

Kubernetes 资源定义

type Deployment struct {
    APIVersion string `yaml:"apiVersion"`
    Kind       string `yaml:"kind"`
    Metadata   struct {
        Name      string `yaml:"name"`
        Namespace string `yaml:"namespace"`
    } `yaml:"metadata"`
    Spec struct {
        Replicas int `yaml:"replicas"`
        Selector struct {
            MatchLabels map[string]string `yaml:"matchLabels"`
        } `yaml:"selector"`
    } `yaml:"spec"`
}

r.GET("/k8s/deployment/:name", func(c *gin.Context) {
    deployment := getDeployment(c.Param("name"))
    c.YAML(http.StatusOK, deployment)
})

CI/CD 配置导出

r.GET("/ci/config", func(c *gin.Context) {
    pipeline := gin.H{
        "stages": []string{"build", "test", "deploy"},
        "build": gin.H{
            "script": []string{"go build -o app .", "go test ./..."},
        },
        "deploy": gin.H{
            "script": []string{"docker build -t myapp .", "docker push myapp"},
        },
    }
    c.YAML(http.StatusOK, pipeline)
})

小结

YAML 响应虽然不如 JSON 常用,但在配置管理、DevOps 工具等场景下还是很实用的。Gin 的 c.YAML() 方法使用起来和其他响应方法一样简单,配合结构体的 yaml tag 可以灵活控制输出格式。