feat(shopping): add Order Management API commands - #253
feat(shopping): add Order Management API commands#253sswaminathan-godaddy wants to merge 14 commits into
Conversation
Add Shopping catalog, checkout, and order commands backed by the direct Order Management Katana service. - Add configurable Shopping service URL resolution. - Request the full Shopping OAuth scope bundle in one consent flow. - Add catalog search/lookup/get and checkout create/get/update/complete. - Require idempotency keys for completion and avoid automatic replays. - Add bounded order-read polling for eventual consistency. - Document the completed-checkout read limitation and direct-service setup. - Add client, resolver, scope, command discovery, and dry-run coverage. Pending: - Register shopping.catalog:read, shopping.checkout:execute, and shopping.order:read for the CLI OAuth client. - Run authenticated Test-tier catalog and checkout checks. - Authorize and execute a real Test-tier completion smoke only when needed. - Switch to front-door routing/PAT exchange when available. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new Shopping HTTP client currently emits transport debug logs that can capture sensitive customer/order payloads, and the top-level help text is slightly misleading about supported env-var overrides.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR introduces a new gddy shopping module that talks directly to the Order Management Shopping API (Katana endpoint) so agents/users can browse the catalog and run checkout → order flows from the CLI while Shopping is not yet front-doored.
Changes:
- Added the
shoppingcommand group with catalog, checkout, and order read commands plus guide/help metadata. - Implemented a dedicated Shopping HTTP client and shared helpers (JSON body/file parsing, idempotency-key validation, bounded polling for eventual consistency).
- Added Shopping API base-URL resolution via
<ENV>_SHOPPING_URL,SHOPPING_URL, andshopping_urlin the environments TOML, plus registered new OAuth scopes.
File summaries
| File | Description |
|---|---|
| rust/src/shopping/order/mod.rs | Adds the shopping order command group wiring. |
| rust/src/shopping/order/get.rs | Implements shopping order get with optional bounded polling. |
| rust/src/shopping/mod.rs | Registers the Shopping module, scopes bundle, and top-level help text. |
| rust/src/shopping/guides/shopping.md | Documents configuration, auth scopes, and recommended workflow. |
| rust/src/shopping/common.rs | Shared helpers for client creation, JSON input, idempotency, and polling. |
| rust/src/shopping/client.rs | New reqwest-based Shopping API client and error mapping. |
| rust/src/shopping/checkout/update.rs | Implements full-replacement checkout update with --body/--file and dry-run. |
| rust/src/shopping/checkout/mod.rs | Adds the shopping checkout command group wiring. |
| rust/src/shopping/checkout/get.rs | Implements shopping checkout get (with guidance not to use post-completion). |
| rust/src/shopping/checkout/create.rs | Implements shopping checkout create with raw JSON input and dry-run. |
| rust/src/shopping/checkout/complete.rs | Implements shopping checkout complete (idempotency required, optional wait-for-order). |
| rust/src/shopping/catalog/search.rs | Implements shopping catalog search with JSON input. |
| rust/src/shopping/catalog/mod.rs | Adds the shopping catalog command group wiring. |
| rust/src/shopping/catalog/lookup.rs | Implements shopping catalog lookup with JSON input. |
| rust/src/shopping/catalog/get.rs | Implements shopping catalog get (product details) with JSON input. |
| rust/src/scopes.rs | Registers Shopping OAuth scopes in the global scope registry. |
| rust/src/main.rs | Wires the Shopping module into the CLI module list. |
| rust/src/environments/shopping.rs | Adds Shopping base-URL resolver with env var precedence + tests. |
| rust/src/environments/mod.rs | Exposes shopping_url resolver from environments module. |
| rust/src/environments/config.rs | Adds shopping_url to environment TOML config struct and defaults. |
Review details
Suppressed comments (1)
rust/src/shopping/client.rs:98
--debug transportlogging of raw response bytes can leak customer/order details (and potentially payment-related fields) when interacting with Shopping. If transport logging is needed, prefer logging only status/headers or implementing explicit redaction for sensitive JSON fields.
let bytes = response.bytes().await?;
cli_engine::transport::debug_log_reqwest_response(status, &headers, &bytes);
- Files reviewed: 20/20 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…d per returned product, including more sensible next steps
Co-Authored-By: Claude <noreply@anthropic.com>
Clarify customer-facing Shopping API terminology, checkout request guidance, completion safety, and order retrieval behavior. Remove endpoint-override setup from the Shopping guide while retaining its actionable runtime configuration error. Co-Authored-By: Claude <noreply@anthropic.com>
…rt... and a few other tweaks
Add catalog currency selection and currency-aware display, preserve full API data for JSON output, and streamline checkout creation through completion. Keep completion single-shot with generated idempotency keys and move order visibility polling to order retrieval. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Dry-run metadata, retry error handling, generated commands, URL construction, and advertised behavior have unresolved correctness issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
rust/src/shopping/checkout/complete.rs:117
- This command does not expose the
--wait-for-orderoption advertised in the PR description, and the handler never callswait_for_orderafter completion. Either implement the bounded completion polling flow or update the PR description so users do not expect this flag.
"Places a real order. Use --payment-instrument for one saved payment instrument, \
or --body/--file for advanced payment or billing-address fields. Use --idempotency-key \
to control retries, or omit it to let gddy generate and return one. The CLI never retries \
completion automatically. Read the resulting order with `shopping order get <order-id> --wait`.",
rust/src/shopping/catalog/search.rs:412
- Values such as
--queryand--cursorare user/API-controlled and are interpolated inside single quotes without escaping. A query likeO'Reillyproduces an invalid next-page command; use structured next-action parameters or a cross-shell-safe quoting helper.
fn append_search_flag(command: &mut String, name: &str, value: Option<&Value>) {
if let Some(value) = value.and_then(Value::as_str) {
command.push_str(&format!(" --{name} '{value}'"));
}
- Files reviewed: 18/18 changed files
- Comments generated: 8
- Review effort level: Balanced
- Render safe cross-platform structured next actions in human output\n- Mark checkout dry runs and preserve non-404 order-read failures\n- Encode dynamic checkout/order path segments\n- Show concise catalog lookup and bounded payment method choices\n- Render final totals only when response currency is available\n- Document the updated checkout experience Co-Authored-By: Claude <noreply@anthropic.com>
Add httpmock coverage for catalog, checkout, and order routes, request metadata, encoded identifiers, empty successes, and HTTP error handling. Also move two existing test modules to the ends of their files to satisfy Clippy's items-after-test-module lint. Co-Authored-By: Claude <noreply@anthropic.com>
| .with_long( | ||
| "Browse GoDaddy products, create/update/complete checkout, and view completed orders.\n\ | ||
| \n\ | ||
| Shopping commands request the required OAuth permissions together so you can \ |
There was a problem hiding this comment.
What does this mean? That it requests all permissions no matter what you do? I am not sure users would understand this text.
There was a problem hiding this comment.
Makes sense... Probably unnecessary.
There was a problem hiding this comment.
Removed the customer-facing permission and scope explanation; required scopes remain internal command metadata.
There was a problem hiding this comment.
I'd suggest soft line breaks, not hard. That's because the markdown renderer takes care of line wrapping based on the terminal width. With explicit hard line breaks, the text is breaking exactly where it is in the markdown file instead, which will not work as well for narrower terminals.
There was a problem hiding this comment.
Will do.
There was a problem hiding this comment.
Rewrote guide prose using soft wraps; explicit continuations remain only in shell examples.
| # Shopping API | ||
|
|
||
| `gddy shopping` integrates with the Shopping API. |
There was a problem hiding this comment.
The CLI is an abstraction over APIs; we should be focused on telling customers what they can do, not which APIs are being called.
There was a problem hiding this comment.
| # Shopping API | |
| `gddy shopping` integrates with the Shopping API. | |
| # Shopping for GoDaddy Products | |
| Use `gddy shopping` commands to purchase GoDaddy's products and review your past purchases. |
There was a problem hiding this comment.
will update
There was a problem hiding this comment.
Reworked the guide around customer outcomes: discover products, manage a cart, place an order, and review purchases.
| ## Authentication | ||
|
|
||
| Every Shopping command requests these OAuth scopes together, so the first command | ||
| can take the customer through one consent flow for the complete lifecycle: | ||
|
|
||
| ```text | ||
| shopping.catalog:read | ||
| shopping.checkout:execute | ||
| shopping.order:read | ||
| ``` | ||
|
|
||
| You can authenticate before running a workflow: | ||
|
|
||
| ```bash | ||
| gddy auth login \ | ||
| --scope shopping.catalog:read \ | ||
| --scope shopping.checkout:execute \ | ||
| --scope shopping.order:read | ||
| ``` | ||
|
|
||
| Shopping requests use the selected environment's standard API front door. OAuth requests the | ||
| complete lifecycle scope bundle above in one consent flow. PAT support requires those Shopping | ||
| scopes to be available on the Developer Portal and is tracked separately. |
There was a problem hiding this comment.
Is any of this something a user needs to know? Users aren't going to have any environments besides prod and in edge cases OTE. They're not going to know what "front door" means. This "is tracked separately" doesn't make sense for users either...
I think this entire guide needs a rewrite so it is geared toward users of the CLI. My suggested outline:
- Introduction, what this guide teaches you (how to buy GoDaddy products)
- Concepts (what's in a catalog, the cart, payment methods, etc. I am writing this before reviewing the whole thing, so whatever concepts the CLI exposes, not the ones I'm speculating on)
- How to accomplish specific tasks (command sequence, explain anything non-obvious)
There was a problem hiding this comment.
SOunds good. Will take another stab at it.
There was a problem hiding this comment.
Rewrote the guide as a customer-focused catalog-to-cart-to-order journey and removed internal environment/front-door material.
| } | ||
|
|
||
| fn next_actions(response: &Value, env: &str) -> Vec<cli_engine::NextAction> { | ||
| let Some(product) = response.get("product") else { |
There was a problem hiding this comment.
If we have a spec, I highly recommend generating code (using progenitor like we did for domains) so that we have strong types instead of working with typeless JSON. That should avoid potential bugs in JSON traversal and make the code less verbose with all the type conversions.
There was a problem hiding this comment.
ok, will look into this
There was a problem hiding this comment.
Added a generated shopping-client crate backed by the authoritative Shopping OpenAPI contract and Progenitor builders.
|
|
||
| const PAYMENT_INSTRUMENT_LIMIT: usize = 5; | ||
|
|
||
| fn available_payment_instruments(checkout: &Value, show_all: bool) -> Vec<Value> { |
There was a problem hiding this comment.
We should have a separate command for listing payment instruments.
There was a problem hiding this comment.
I agree, but it's a bit complicated.. Applicable payment methods are really specific to the checkout context. For instance, if the currency were to change, it could potentially change the available payment options - this is how FOS works as well (and perhaps why UCP doesn't have a separate way to get available payments).
If anything, let's defer explicit commands for this for first release. I will try to make the guide better to help users understand the flow easily.
There was a problem hiding this comment.
If we want, I can expose a command that lists available payments in a checkout session.
There was a problem hiding this comment.
Deferred a standalone payment-method command for this release: eligible methods are cart-specific. Cart create/get exposes the contextual choices and IDs.
| saved instrument for selection at completion. | ||
|
|
||
| A stored payment instrument normally supplies its saved billing address automatically. Use a | ||
| JSON document when you need an address override or other advanced nested fields: |
There was a problem hiding this comment.
I'm not sure a sample JSON document makes sense. If JSON is being used, that would be something an AI agent would probably need to do for the human, and the AI agent should have a schema so it knows the shape of the JSON. Same for all these other advanced options.
I'd suggest either omitting these JSON/file parameters or at least having the guide link agents to where they can get the JSON schema.
There was a problem hiding this comment.
ok, maybe just stick to simple inputs all the way through then... at least for now... will address
There was a problem hiding this comment.
Removed raw JSON walkthroughs from the guide; the main journey now uses only simple command inputs. Advanced inputs remain available for exceptional use.
There was a problem hiding this comment.
Why not use the progenitor pattern here instead of manually traversing JSON and risking mismatch with the spec?
There was a problem hiding this comment.
Sounds good (I personally had no idea there's such a thing - just went with Claude's impl as long as the testing achieved the outcome)
There was a problem hiding this comment.
Migrated Shopping transport and request modeling to a generated Progenitor client; dynamic JSON remains only at the CLI projection/compatibility boundary.
| @@ -0,0 +1,107 @@ | |||
| use serde_json::Value; | |||
|
|
|||
| /// Shopping amounts are ISO-4217 minor units. Their decimal scale derives from the returned | |||
There was a problem hiding this comment.
Make sure we're not duplicating the currency formatting we already have for domains. If it's the same standard, we're using a library that understands the standard.
There was a problem hiding this comment.
Will address
There was a problem hiding this comment.
Consolidated ISO-4217 minor-unit formatting on the existing Domains implementation; Shopping retains only its response-shape extraction.
| /// Mirrors cli-engine placeholder substitution for custom human views. The | ||
| /// structured template and parameters remain in the output envelope. |
There was a problem hiding this comment.
Claude... why do you keep "mirroring" functionality (duplicating) instead of reusing what we already have? We already have a standard output envelope to include these actions in a standard way. If we really need to duplicate code, we need a better explanation on why that is necessary.
There was a problem hiding this comment.
Agreed! will have it take a closer look.
There was a problem hiding this comment.
Removed project-local next-action display/substitution logic. cli-engine now renders standard structured next-action footers for custom views.
Co-Authored-By: Claude <noreply@anthropic.com>
Objective
Expose the Shopping API through
gddyso agents and customers can browse the catalog, create and complete checkouts, and retrieve completed orders.Shopping requests use the selected environment's standard GoDaddy API front door and obtain the complete lifecycle OAuth scope bundle in one consent flow. PAT support requires Shopping scopes to be made available in the Developer Portal and is tracked separately.
What changed
gddy shoppingcommand group:catalog search,catalog lookup,catalog getcheckout create,checkout get,checkout update,checkout completeorder getshopping.catalog:readshopping.checkout:executeshopping.order:read--body/--fileretained for advanced requests.shopping order get <order-id> --waitowns bounded eventual-consistency polling.Validation
Executed from
rust/:All checks passed.
cargo test --workspacepassed with 819 tests across the workspace, plus 17 ignored tests and no failures.Also verified the deployed Test Shopping API through the standard front door for catalog discovery, checkout creation/completion, and order retrieval. A GBP end-to-end purchase produced a GBP order with expected final totals.
Pending / follow-up
shopping.*scopes available to Personal Access Token creation in the Developer Portal, then add Shopping PAT support.🤖 Generated with Claude Code