Skip to content

refactor(proto)!: use Connector enum for Apple Pay session token connector field - #2128

Open
Utkal059 wants to merge 4 commits into
juspay:mainfrom
Utkal059:proto/applepay-session-connector-enum
Open

refactor(proto)!: use Connector enum for Apple Pay session token connector field#2128
Utkal059 wants to merge 4 commits into
juspay:mainfrom
Utkal059:proto/applepay-session-connector-enum

Conversation

@Utkal059

@Utkal059 Utkal059 commented Aug 13, 2026

Copy link
Copy Markdown

Description

ApplepayClientAuthenticationResponse.connector was string, even though every caller
fills it in with a connector name that already exists as a variant of the Connector enum
in the same file. This makes it Connector.

Currency, CountryAlpha2 and SdkNextAction are already carried as proto enums on this
message, so the string was the odd one out.

Changes:

  • payment.protostring connector = 3; becomes Connector connector = 3; on
    ApplepayClientAuthenticationResponse.
  • domain_types/connector_types.rs — the matching domain field becomes ConnectorEnum.
  • braintree / trustpay transformers — the two connectors that build an Apple Pay session
    token now pass ConnectorEnum::Braintree / ConnectorEnum::Trustpay instead of
    BRAINTREE_CONNECTOR_NAME.to_string() / "trustpay".to_string(). Same value at runtime;
    BRAINTREE_CONNECTOR_NAME stays, since the Google Pay and PayPal responses on the same
    message still use it.
  • domain_types/types.rs — a new ForeignTryFrom<ConnectorEnum> for
    grpc_api_types::payments::Connector, used by both grpc conversion sites. It resolves
    through the SCREAMING_SNAKE_CASE name exactly like the existing CountryAlpha2
    conversion, and returns UnexpectedResponseError rather than falling back to
    CONNECTOR_UNSPECIFIED, so a missing mapping surfaces as an error instead of an
    unusable session token.

I scoped this to the Apple Pay message to keep it symmetric with the hyperswitch PR.
GooglePaySessionResponse.connector, GooglePayThirdPartySdk.connector and
PaypalClientAuthenticationResponse.connector are still string and have the same
problem — happy to follow up on those separately if you want them moved too.

Motivation and Context

Follow-up to review feedback on juspay/hyperswitch#13481, which changes the same field
on hyperswitch's ApplepaySessionTokenResponse from String to hyperswitch's Connector
enum. Because UCS sends the field as a string, that PR currently has to parse it at the
boundary with Connector::from_str. @hrithikesh026 pointed out that this couples
hyperswitch to UCS's serialization format, and @Nithin1506200 asked for the enum change to
be made here so the conversion becomes explicit on both sides.

Ordering: this lands and gets tagged first, then hyperswitch#13481 bumps
unified-connector-service-client and reads the enum directly.

Additional Changes

  • This PR modifies the API contract
  • This PR modifies application configuration/environment variables

This is a wire-breaking change on field 3 (string is length-delimited, an enum is a
varint), so buf breaking will fail under the FILE ruleset. Per the guidance the
proto-checks job prints, that means the PR needs the proto-breaking-approved label — I
can't add it myself.

Heads up on a conflict between two of your workflows, which cost me a red check here: the
Fail on unapproved breaking change step in proto-checks.yml tells you to "use proto!:
as the PR title type", but Verify PR title follows conventional commit standards rejects
it with Commit type `proto` not allowed. That job runs on pull_request_target with no
checkout step (deliberately, per the comment at the top of the file), so cog.toml — where
proto is registered as a commit type — is never on disk, and cocogitto falls back to its
built-in types. Every merged proto change I looked at uses the scope form instead
(feat(proto):, fix(proto):), so I've retitled this one refactor(proto)!:. Either the
proto-checks message or the title job's config probably wants a fix.

The one checklist item that isn't satisfied yet is "migration PR is already merged and
deployed": hyperswitch#13481 is open, and pins UCS by git tag, so it won't see this change
until it bumps the tag. That's the sequence @Nithin1506200 proposed on that PR ("we will
get it merged and you can bump it here later"), but if you'd rather not break the wire at
all, the alternative is the additive route the same job suggests — add
Connector connector_type = 9;, mark field 3 [deprecated = true], and drop it in a
follow-up once consumers have moved. Say the word and I'll rework it that way.

Also worth flagging, found while checking the mapping is total: ConnectorEnum::RazorpayV2
and ConnectorEnum::Affirm have no counterpart in the proto Connector enum (there is
RAZORPAY but no RAZORPAY_V2, and no AFFIRM at all). Today
grpc_connector_from_connector_enum quietly turns both into CONNECTOR_UNSPECIFIED.
Neither serves an Apple Pay session, so nothing here regresses, but it's a pre-existing gap
worth a separate look.

How did you test it?

Added apple_pay_session_connectors_map_to_their_proto_variants in
domain_types/src/types.rs, covering the only two connectors that build an Apple Pay
session token — it asserts ConnectorEnum::Braintree and ConnectorEnum::Trustpay land on
Connector::Braintree and Connector::Trustpay, which is what breaks if either side is
renamed.

On the hyperswitch side, hyperswitch#13481 has a matching test pinning "braintree" and
"trustpay" as the exact strings UCS sends today.

I wasn't able to run the full cargo clippy / cargo nextest matrix locally — this
workspace needs more memory than my machine has — so I'm relying on CI for those and will
turn around anything that comes back red. cargo +nightly fmt --check is clean on every
file I touched.

`ApplepayClientAuthenticationResponse.connector` was a free-form string that
every caller filled in with the connector's snake_case name, so an invalid value
could only be caught on the far side of the wire. It is now the `Connector` enum
the proto already defines, which is how `Currency`, `CountryAlpha2` and
`SdkNextAction` are already carried on this message.

Domain-side the field becomes `ConnectorEnum`, and braintree and trustpay -- the
two connectors that build an Apple Pay session token -- pass the variant instead
of a string literal. A new `ForeignTryFrom<ConnectorEnum>` for the proto
`Connector` does the domain -> proto mapping through the SCREAMING_SNAKE_CASE
name, mirroring the existing `CountryAlpha2` conversion, and errors rather than
falling back to `CONNECTOR_UNSPECIFIED`.

This changes the wire type of field 3, so `buf breaking` will flag it and the PR
needs the `proto-breaking-approved` label. The consumer migration is
juspay/hyperswitch#13481, which switches the same field on
`ApplepaySessionTokenResponse` to hyperswitch's `Connector` enum and will bump
the `unified-connector-service-client` tag once this lands.
@Utkal059
Utkal059 requested review from a team as code owners August 13, 2026 22:03
Copilot AI lite review requested due to automatic review settings August 13, 2026 22:03
@Utkal059 Utkal059 changed the title proto!: use Connector enum for Apple Pay session token connector field refactor(proto)!: use Connector enum for Apple Pay session token connector field Aug 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Apple Pay client-auth/session-token payload to carry the connector as a protobuf Connector enum instead of a free-form string, aligning the gRPC contract with existing enum usage and making connector mapping explicit at conversion boundaries.

Changes:

  • Changed ApplepayClientAuthenticationResponse.connector in payment.proto from string to Connector (enum).
  • Updated domain model + gRPC conversion to use ConnectorEnum and added a ForeignTryFrom<ConnectorEnum> mapping to the proto enum (with a unit test).
  • Updated Braintree and Trustpay Apple Pay session-token builders to pass ConnectorEnum::{Braintree, Trustpay}.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
crates/types-traits/grpc-api-types/proto/payment.proto Wire-contract change: Apple Pay connector field is now a proto enum.
crates/types-traits/domain_types/src/types.rs Converts ConnectorEnum to proto Connector during Apple Pay gRPC response building; adds test coverage.
crates/types-traits/domain_types/src/connector_types.rs Domain Apple Pay response now stores connector as ConnectorEnum.
crates/integrations/connector-integration/src/connectors/trustpay/transformers.rs Uses ConnectorEnum::Trustpay when constructing Apple Pay session token data.
crates/integrations/connector-integration/src/connectors/braintree/transformers.rs Uses ConnectorEnum::Braintree when constructing Apple Pay session token data.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 5363 to 5366
pub payment_request_data: Option<ApplePayPaymentRequest>,
/// The session token is w.r.t this connector
pub connector: String,
pub connector: ConnectorEnum,
/// Identifier for the delayed session response
.map(grpc_api_types::payments::ApplePayPaymentRequest::foreign_try_from)
.transpose()?,
connector: apple_pay_token.connector,
connector: grpc_api_types::payments::Connector::foreign_try_from(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets propagate the String to enum change through out the code base. lets not keep room open for any kind of String -> Enum conversion.

The domain -> proto direction was a name lookup:
`Connector::from_str_name(&connector.to_string().to_ascii_uppercase())`.
That is the same String -> enum conversion this PR set out to remove,
only moved one layer down: it can only fail at runtime, and it lets the
two enums drift apart without anything noticing.

It is now an exhaustive match, mirroring the grpc -> domain
`ForeignTryFrom<Connector> for ConnectorEnum` that already lives in
`connector_types.rs`. With no wildcard arm, a new `ConnectorEnum`
variant stops compiling until it is mapped. That matters here: the
grpc -> domain impl does carry a wildcard, and has quietly fallen
behind on `netcetera`, `worldpayvantiv`, `paybox` and `absa_sanlam`,
all four of which exist on both sides and are mapped in this direction.

`razorpay_v2` and `affirm` have no proto `Connector` variant at all, so
they are named explicitly and still return an error rather than being
swept up by a wildcard.

Also drops `grpc_connector_from_connector_enum`, an unreferenced helper
running the same name lookup with a silent `CONNECTOR_UNSPECIFIED`
fallback -- the last place in the tree this conversion could come back.
@Utkal059
Utkal059 requested a review from a team as a code owner August 28, 2026 15:56
…open

`main` gained `moneris`, `citigate`, `ilixium` and `worldpayraft` since
this branch forked. Because the domain -> proto mapping is now an
exhaustive match rather than a name lookup, merging main in stopped the
build with E0004 instead of quietly resolving all four to
`CONNECTOR_UNSPECIFIED` -- which is exactly the drift the previous
commit set out to make impossible.

All four already exist in the proto `Connector` enum, so all four are
mapped. `razorpay_v2` and `affirm` are still the only two without a
proto counterpart.
@Utkal059

Utkal059 commented Aug 28, 2026

Copy link
Copy Markdown
Author

@hrithikesh026 Done — the domain → proto mapping is now an exhaustive match, mirroring the ForeignTryFrom<Connector> for ConnectorEnum in connector_types.rs. No from_str_name, no to_string(), no wildcard, so a new ConnectorEnum variant won't compile until it's mapped. razorpay_v2 and affirm have no proto variant, so they're named explicitly and still error.

It paid off immediately: merging main broke the build with E0004 on moneris, citigate, ilixium and worldpayraft, which landed while this branch was open — under the old lookup all four would have silently become CONNECTOR_UNSPECIFIED. All mapped now, and Compilation Check + Clippy are green.

Also dropped grpc_connector_from_connector_enum (composite-service/utils.rs) — same name lookup with a silent CONNECTOR_UNSPECIFIED fallback, unreferenced anywhere in the tree. Happy to restore it if it's kept for something I can't see.

Noticed but left alone: the grpc → domain match's _ => wildcard has fallen behind on netcetera, worldpayvantiv, paybox and absa_sanlam — all four exist on both sides but return InvalidDataFormat. Happy to fix here or separately.

@Nithin1506200 this is the UCS PR you asked for. Two things I can't do from my side:

  • Proto checks needs the proto-breaking-approved label — the gate in proto-checks.yml is label-only. Field 3's retype is the intended break; consumer migration is refactor(api_models): use Connector enum for Apple Pay session token connector field hyperswitch#13481 and the ordering is in the description. If you'd rather keep string connector = 3 [deprecated = true] and add a new enum field instead, say the word and I'll rework it.
  • Code owner review from @juspay/connector-service-proto-maintainers (proto), @juspay/connector-service-framework (domain_types) and @juspay/connector-service-connectors (braintree/trustpay).

SDK Tests is red on every fork PR — no CONNECTOR_SPECIFIC_AUTH, so creds.json is never written. Unrelated to this diff; #2129 covers the gRPC half of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants