[object Object]

← back to Cli Printing Press

fix(cli): add smart-default table output for POST endpoints (#66)

797049f53c8b16a19e6c599ec115d54bbe1a94be · 2026-03-29 22:13:19 -0700 · Trevin Chow

* fix(cli): add smart-default table output for POST endpoints

The smart-default table rendering (PR #60) only applied to GET endpoints.
POST endpoints that return browseable arrays (like search) got raw JSON
in the terminal. Now POST responses are also checked: if the response is
an array of objects (directly or wrapped in a "data" field), it renders
as a table in the terminal. Falls through to the envelope path for
non-array responses.

This is a heuristic — no spec annotation needed. Any POST that returns
array data gets table rendering automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): log warning when table rendering fails instead of silent fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 797049f53c8b16a19e6c599ec115d54bbe1a94be
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sun Mar 29 22:13:19 2026 -0700

    fix(cli): add smart-default table output for POST endpoints (#66)
    
    * fix(cli): add smart-default table output for POST endpoints
    
    The smart-default table rendering (PR #60) only applied to GET endpoints.
    POST endpoints that return browseable arrays (like search) got raw JSON
    in the terminal. Now POST responses are also checked: if the response is
    an array of objects (directly or wrapped in a "data" field), it renders
    as a table in the terminal. Falls through to the envelope path for
    non-array responses.
    
    This is a heuristic — no spec annotation needed. Any POST that returns
    array data gets table rendering automatically.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    * fix(cli): log warning when table rendering fails instead of silent fallback
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 .../generator/templates/command_endpoint.go.tmpl     | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/internal/generator/templates/command_endpoint.go.tmpl b/internal/generator/templates/command_endpoint.go.tmpl
index c51fb786..c50ccc19 100644
--- a/internal/generator/templates/command_endpoint.go.tmpl
+++ b/internal/generator/templates/command_endpoint.go.tmpl
@@ -155,6 +155,26 @@ func new{{camel .FuncPrefix}}{{camel .EndpointName}}Cmd(flags *rootFlags) *cobra
 {{- end}}
 
 {{- if not (or (eq .Endpoint.Method "GET") (eq .Endpoint.Method "HEAD"))}}
+			if wantsHumanTable(cmd.OutOrStdout(), flags) {
+				// Check if response contains an array (directly or wrapped in "data")
+				var items []map[string]any
+				if json.Unmarshal(data, &items) == nil && len(items) > 0 {
+					if err := printAutoTable(cmd.OutOrStdout(), items); err != nil {
+						fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
+					} else {
+						return nil
+					}
+				} else {
+					var wrapped struct{ Data []map[string]any `json:"data"` }
+					if json.Unmarshal(data, &wrapped) == nil && len(wrapped.Data) > 0 {
+						if err := printAutoTable(cmd.OutOrStdout(), wrapped.Data); err != nil {
+							fmt.Fprintf(os.Stderr, "warning: table rendering failed, falling back to JSON: %v\n", err)
+						} else {
+							return nil
+						}
+					}
+				}
+			}
 			if flags.asJSON || !isTerminal(cmd.OutOrStdout()) {
 				if flags.quiet {
 					return nil

← f0bb0de2 feat(cli): add proxy-envelope client pattern to generator (#  ·  back to Cli Printing Press  ·  fix(cli): write .printing-press.json manifest during generat 154626ed →