{
  "slug": "consume-go",
  "title": "Consume from Go",
  "description": "Read @webhouse/cms content from Go — Hugo themes, Gin handlers, and standard library file I/O.",
  "category": "consumers",
  "order": 13,
  "locale": "en",
  "translationGroup": "61fe1f5f-06d8-4a05-9d72-573c00be5405",
  "helpCardId": null,
  "content": "## Setup\n\n```\nmy-project/\n  cms.config.ts\n  content/          # JSON documents\n  public/uploads/\n  main.go\n  templates/\n```\n\n## Reader package\n\nCreate `internal/webhouse/webhouse.go`:\n\n```go\npackage webhouse\n\nimport (\n    \"encoding/json\"\n    \"os\"\n    \"path/filepath\"\n    \"sort\"\n    \"strings\"\n)\n\ntype Document struct {\n    ID               string                 `json:\"id\"`\n    Slug             string                 `json:\"slug\"`\n    Status           string                 `json:\"status\"`\n    Locale           string                 `json:\"locale,omitempty\"`\n    TranslationGroup string                 `json:\"translationGroup,omitempty\"`\n    Data             map[string]interface{} `json:\"data\"`\n    CreatedAt        string                 `json:\"createdAt,omitempty\"`\n    UpdatedAt        string                 `json:\"updatedAt,omitempty\"`\n}\n\ntype Client struct {\n    ContentDir string\n}\n\nfunc New(contentDir string) *Client {\n    return &Client{ContentDir: contentDir}\n}\n\nfunc (c *Client) Collection(name, locale string) ([]Document, error) {\n    dir := filepath.Join(c.ContentDir, name)\n    entries, err := os.ReadDir(dir)\n    if err != nil {\n        return nil, err\n    }\n\n    var docs []Document\n    for _, e := range entries {\n        if !strings.HasSuffix(e.Name(), \".json\") {\n            continue\n        }\n        raw, err := os.ReadFile(filepath.Join(dir, e.Name()))\n        if err != nil {\n            continue\n        }\n        var d Document\n        if err := json.Unmarshal(raw, &d); err != nil {\n            continue\n        }\n        if d.Status != \"published\" {\n            continue\n        }\n        if locale != \"\" && d.Locale != locale {\n            continue\n        }\n        docs = append(docs, d)\n    }\n\n    // Sort by date desc\n    sort.Slice(docs, func(i, j int) bool {\n        di, _ := docs[i].Data[\"date\"].(string)\n        dj, _ := docs[j].Data[\"date\"].(string)\n        return di > dj\n    })\n    return docs, nil\n}\n\nfunc (c *Client) Document(collection, slug string) (*Document, error) {\n    path := filepath.Join(c.ContentDir, collection, slug+\".json\")\n    raw, err := os.ReadFile(path)\n    if err != nil {\n        return nil, err\n    }\n    var d Document\n    if err := json.Unmarshal(raw, &d); err != nil {\n        return nil, err\n    }\n    if d.Status != \"published\" {\n        return nil, nil\n    }\n    return &d, nil\n}\n\nfunc (c *Client) FindTranslation(doc *Document, collection string) (*Document, error) {\n    if doc.TranslationGroup == \"\" {\n        return nil, nil\n    }\n    docs, err := c.Collection(collection, \"\")\n    if err != nil {\n        return nil, err\n    }\n    for _, other := range docs {\n        if other.TranslationGroup == doc.TranslationGroup && other.Locale != doc.Locale {\n            return &other, nil\n        }\n    }\n    return nil, nil\n}\n```\n\n## Gin handler\n\n```go\npackage main\n\nimport (\n    \"html/template\"\n    \"net/http\"\n\n    \"github.com/gin-gonic/gin\"\n    \"myproject/internal/webhouse\"\n)\n\nfunc main() {\n    wh := webhouse.New(\"content\")\n    r := gin.Default()\n    r.LoadHTMLGlob(\"templates/*\")\n    r.Static(\"/uploads\", \"./public/uploads\")\n\n    r.GET(\"/\", func(c *gin.Context) {\n        posts, _ := wh.Collection(\"posts\", \"en\")\n        c.HTML(http.StatusOK, \"home.html\", gin.H{\"Posts\": posts})\n    })\n\n    r.GET(\"/blog/:slug\", func(c *gin.Context) {\n        post, _ := wh.Document(\"posts\", c.Param(\"slug\"))\n        if post == nil {\n            c.AbortWithStatus(404)\n            return\n        }\n        c.HTML(http.StatusOK, \"post.html\", gin.H{\"Post\": post})\n    })\n\n    r.Run(\":8080\")\n}\n```\n\n## Template\n\n```html\n<!-- templates/post.html -->\n<article>\n  <h1>{{ index .Post.Data \"title\" }}</h1>\n  <time>{{ index .Post.Data \"date\" }}</time>\n  <div class=\"prose\">\n    {{ index .Post.Data \"content\" | markdown }}\n  </div>\n</article>\n```\n\n## Hugo integration\n\nHugo uses its own content system, but you can write a small script that converts @webhouse/cms JSON to Hugo's front matter + markdown format at build time:\n\n```go\n// scripts/sync-to-hugo.go\nfunc main() {\n    wh := webhouse.New(\"content\")\n    posts, _ := wh.Collection(\"posts\", \"\")\n    for _, p := range posts {\n        frontMatter := fmt.Sprintf(\"---\\ntitle: %q\\ndate: %s\\n---\\n\\n%s\\n\",\n            p.Data[\"title\"], p.Data[\"date\"], p.Data[\"content\"])\n        os.WriteFile(fmt.Sprintf(\"hugo/content/posts/%s.md\", p.Slug), []byte(frontMatter), 0644)\n    }\n}\n```\n\nRun this before `hugo build` to sync content.\n\n## Caching\n\nUse a `sync.Map` or in-memory cache with TTL:\n\n```go\nvar cache sync.Map\n\nfunc (c *Client) CollectionCached(name, locale string) ([]Document, error) {\n    key := name + \":\" + locale\n    if v, ok := cache.Load(key); ok {\n        return v.([]Document), nil\n    }\n    docs, err := c.Collection(name, locale)\n    if err != nil {\n        return nil, err\n    }\n    cache.Store(key, docs)\n    return docs, nil\n}\n```\n\n## Next steps\n\n- See the [Go example](https://github.com/webhousecode/cms/tree/main/examples/consumers/go-gin)\n- Learn about [Framework-Agnostic Architecture](/docs/framework-agnostic)",
  "excerpt": "Setup\n\n\nmy-project/\n  cms.config.ts\n  content/           JSON documents\n  public/uploads/\n  main.go\n  templates/\n\n\n Reader package\n\nCreate internal/webhouse/webhouse.go:\n\ngo\npackage webhouse\n\nimport (\n    \"encoding/json\"\n    \"os\"\n    \"path/filepath\"\n    \"sort\"\n    \"strings\"\n)\n\ntype Document struct {",
  "seo": {
    "metaTitle": "Consume from Go — webhouse.app Docs",
    "metaDescription": "Read @webhouse/cms content from Go — Hugo themes, Gin handlers, and standard library file I/O.",
    "keywords": [
      "webhouse",
      "cms",
      "go",
      "golang",
      "gin",
      "hugo",
      "consumer"
    ]
  },
  "createdAt": "2026-04-08T12:00:00.000Z",
  "updatedAt": "2026-04-08T12:00:00.000Z"
}