◐ Off-By-One · answer catalog

go-api-validation-message

2 answer(s)godockergodocker

go-api-validation-message

📦 Source in repository (JSON)

Answer 1

Built the API from scratch in ~/go-api-validation-message (Go 1.26, stdlib only, zero deps).

Root cause: the old validator reported the first missing nested field (memory_payload.body_text is required) and stopped — when the parent container was absent it never told callers about the container or the sibling fields, so a natural {} body leaked only one baffling dot-path.

Fix (main.go): - validateCreateMemory now walks the full schema and returns every missing required path. Critically, when a parent container is missing it also enumerates all required descendants — {} yields all 4 paths:

if req.MemoryPayload == nil {
    missing = append(missing, "memory_payload", "memory_payload.body_text")
} else if strings.TrimSpace(req.MemoryPayload.BodyText) == "" {
    missing = append(missing, "memory_payload.body_text")
}
{"error":{"code":"validation_failed",
  "message":"Missing required field(s): memory_payload, memory_payload.body_text, scope_context, scope_context.tenant",
  "missing_fields":["memory_payload","memory_payload.body_text","scope_context","scope_context.tenant"]}}
{ "scope_context":  { "tenant": "acme-corp" },
  "memory_payload": { "body_text": "File the Q3 report by Friday." } }

Evidence & signatures

Verified via `go vet`, `gofmt`, unit/E2E tests (`go test -v`, 5 tests all PASS), plus a **live server** run on port 8091 with curl:

| Case | Result |
|---|---|
| `{}` | `400` — message + `missing_fields` enumerate **all 4** paths ✅ |
| Documented body (exact README Quick Start body) | `201` with stored memory, tenant + body_text echoed ✅ |
| `{"scope_context":{"tenant":"acme"}}` (partial) | `400` — only `memory_payload`, `memory_payload.body_text` (still exhaustive for that subtree) ✅ |
| `{"scope_context":{}}` + full payload | `400` — only `scope_context.tenant` ✅ |
| Malformed JSON `{"scope_context": ` | `400` — falls back to full 4-field schema ✅ |
| `POST /v1/memories?tenant=acme` (query param on write) | ignored — body still validated (400 without payload) ✅ |
| `GET /v1/memories?tenant=acme` | `200` ✅ |
| whitespace-only values (`""`, `"  "`) | treated as missing (`TrimSpace`) ✅ |

`TestEmptyBodyEnumeratesAllRequiredFields` is the headline regression test: it asserts both the exact `missing_fields` set and that the message text contains every field name. Also `TestDocumentedBodyCreates` pins the README body to `201`, so the doc can't drift.
{"model": "deepseek-v4-flash", "problem_class": "go-api-validation-message", "result": "passed", "tests": 5}

Answer 2

Built the API from scratch in ~/go-api-validation-message (Go 1.26, stdlib only, zero deps).

Root cause: the old validator reported the first missing nested field (memory_payload.body_text is required) and stopped — when the parent container was absent it never told callers about the container or the sibling fields, so a natural {} body leaked only one baffling dot-path.

Fix (main.go): - validateCreateMemory now walks the full schema and returns every missing required path. Critically, when a parent container is missing it also enumerates all required descendants — {} yields all 4 paths:

if req.MemoryPayload == nil {
    missing = append(missing, "memory_payload", "memory_payload.body_text")
} else if strings.TrimSpace(req.MemoryPayload.BodyText) == "" {
    missing = append(missing, "memory_payload.body_text")
}
{"error":{"code":"validation_failed",
  "message":"Missing required field(s): memory_payload, memory_payload.body_text, scope_context, scope_context.tenant",
  "missing_fields":["memory_payload","memory_payload.body_text","scope_context","scope_context.tenant"]}}
{ "scope_context":  { "tenant": "acme-corp" },
  "memory_payload": { "body_text": "File the Q3 report by Friday." } }

Evidence & signatures

Verified via `go vet`, `gofmt`, unit/E2E tests (`go test -v`, 5 tests all PASS), plus a **live server** run on port 8091 with curl:

| Case | Result |
|---|---|
| `{}` | `400` — message + `missing_fields` enumerate **all 4** paths ✅ |
| Documented body (exact README Quick Start body) | `201` with stored memory, tenant + body_text echoed ✅ |
| `{"scope_context":{"tenant":"acme"}}` (partial) | `400` — only `memory_payload`, `memory_payload.body_text` (still exhaustive for that subtree) ✅ |
| `{"scope_context":{}}` + full payload | `400` — only `scope_context.tenant` ✅ |
| Malformed JSON `{"scope_context": ` | `400` — falls back to full 4-field schema ✅ |
| `POST /v1/memories?tenant=acme` (query param on write) | ignored — body still validated (400 without payload) ✅ |
| `GET /v1/memories?tenant=acme` | `200` ✅ |
| whitespace-only values (`""`, `"  "`) | treated as missing (`TrimSpace`) ✅ |

`TestEmptyBodyEnumeratesAllRequiredFields` is the headline regression test: it asserts both the exact `missing_fields` set and that the message text contains every field name. Also `TestDocumentedBodyCreates` pins the README body to `201`, so the doc can't drift.
{"model": "deepseek-v4-flash", "problem_class": "go-api-validation-message", "result": "passed", "tests": 5}
Generated from the verified corpus · MIT licensedBack to the catalog