Files
tmpl-test-go/main.go
Scaffolder e868792eda
All checks were successful
Build and Push to ACR / Platform guard (push) Successful in 5s
Build and Push to ACR / Build and Push (push) Has been skipped
initial commit
Change-Id: Ied1b5f2137f2b5f803d5411235607bd27c5e57ba
2026-03-24 10:43:21 +00:00

164 lines
4.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"strings"
"sync"
"sync/atomic"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// ---------------------------------------------------------------------------
// Domain model
// ---------------------------------------------------------------------------
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
type ItemRequest struct {
Name string `json:"name"`
Description string `json:"description"`
}
// ---------------------------------------------------------------------------
// In-memory store
// ---------------------------------------------------------------------------
var (
store sync.Map
counter atomic.Int64
)
func nextID() int {
return int(counter.Add(1))
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(v)
}
func itemIDFromPath(path string) (int, bool) {
parts := strings.Split(strings.TrimSuffix(path, "/"), "/")
if len(parts) < 3 {
return 0, false
}
id, err := strconv.Atoi(parts[len(parts)-1])
return id, err == nil
}
// ---------------------------------------------------------------------------
// Handlers
// ---------------------------------------------------------------------------
func healthHandler(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"status": "UP"})
}
func itemsHandler(w http.ResponseWriter, r *http.Request) {
// Route: /api/items or /api/items/{id}
hasSub := strings.Count(strings.TrimSuffix(r.URL.Path, "/"), "/") >= 3
if hasSub {
id, ok := itemIDFromPath(r.URL.Path)
if !ok {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid id"})
return
}
switch r.Method {
case http.MethodGet:
v, exists := store.Load(id)
if !exists {
writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
return
}
writeJSON(w, http.StatusOK, v)
case http.MethodPut:
var req ItemRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
existingRaw, exists := store.Load(id)
if !exists {
writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"})
return
}
existing := existingRaw.(Item)
if req.Name == "" {
req.Name = existing.Name
}
if req.Description == "" {
req.Description = existing.Description
}
updated := Item{ID: id, Name: req.Name, Description: req.Description}
store.Store(id, updated)
writeJSON(w, http.StatusOK, updated)
case http.MethodDelete:
store.Delete(id)
writeJSON(w, http.StatusOK, map[string]int{"deleted": id})
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
return
}
// /api/items — list or create
switch r.Method {
case http.MethodGet:
var items []Item
store.Range(func(_, v any) bool {
items = append(items, v.(Item))
return true
})
if items == nil {
items = []Item{}
}
writeJSON(w, http.StatusOK, items)
case http.MethodPost:
var req ItemRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
if req.Name == "" {
req.Name = "unnamed"
}
item := Item{ID: nextID(), Name: req.Name, Description: req.Description}
store.Store(item.ID, item)
writeJSON(w, http.StatusCreated, item)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", healthHandler)
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/api/items/", itemsHandler)
mux.HandleFunc("/api/items", itemsHandler)
addr := ":8080"
fmt.Printf("tmpl-test-go listening on %s\n", addr)
log.Fatal(http.ListenAndServe(addr, mux))
}