Skip to content

Add programmatic API-shape output: --raw flag + --params passthrough #188

@omriariav

Description

@omriariav

Motivation

Today the CLI is great for interactive/ergonomic use, but scripts that integrate with gws end up needing the raw Google API JSON shape (Gmail API, Chat API, People API payloads as documented by Google). Two friction points hit programmatic consumers:

  1. Output is flattened/transformed — fields are renamed, base64 bodies are decoded, header arrays are collapsed, etc. Great for humans, lossy for machines that already speak the API.
  2. Not every API param is exposed as a flag — e.g. Chat API's filter parameter supports expressions like createTime > "2025-01-01T00:00:00Z" or spaceType = "DIRECT_MESSAGE" that aren't accessible from the current flag surface.

Adding a small programmatic mode would unblock scripting/automation use cases without disturbing the existing ergonomic UX.

Proposed changes

1. Global --raw flag

When --raw is set on a resource command, return the unmodified Google API response JSON instead of the flattened/pretty shape. Implementation-wise: skip the transform layer between SDK response and stdout.

2. --params <json> escape hatch on resource commands

Accept a JSON object that maps to the underlying API request's parameters. Merges with / overrides any flag-derived params. Example:

gws chat messages list --params '{\"parent\":\"spaces/AAA\",\"pageSize\":100,\"filter\":\"createTime > \\\"2025-01-01T00:00:00Z\\\"\"}' --raw

This avoids having to flag-ify every API parameter and unblocks features like Chat filters immediately.

3. Pagination under --raw

--all should aggregate across pages while preserving API shape:

  • Concatenate top-level list fields (messages, spaces, members, ...) across pages
  • Drop nextPageToken from the final aggregated output

NDJSON (one page object per line) is an acceptable alternative — easy for callers to merge.

Endpoints that matter most for programmatic use

Command Underlying API Notes
gmail list users.messages.list needs q, maxResults, pagination
gmail thread <id> users.threads.get needs full payload tree: headers, parts[*].body.data (base64), internalDate, labelIds
chat spaces list spaces.list needs filter (DM filter especially)
chat members list spaces.members.list needs parent, pagination
chat messages list spaces.messages.list needs parent, filter (createTime), pagination
people get people.get needs resourceName, personFields

These cover the highest-value programmatic use cases. Other resources can follow the same pattern incrementally.

Backwards compatibility

  • --raw is opt-in; default behavior unchanged.
  • --params is additive; existing flags continue to work and take precedence (or merge — designer's call).
  • No change to auth, config, or command structure.

Why this matters

Right now, programmatic consumers either (a) reach past the CLI directly to the Google SDK, or (b) reverse-engineer the flattened shape and write fragile decoders. Both defeat the value of having a unified CLI. --raw + --params makes the CLI a first-class building block for scripts and pipelines without compromising the human-friendly default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions