Skip to content

[CDX-566] Migrate to v2 search submit endpoint - #286

Open
TarekAlQaddy wants to merge 3 commits into
masterfrom
cdx-566-swift-sdk-search-search-submitted-parity-fixes
Open

TarekAlQaddy wants to merge 3 commits into
masterfrom
cdx-566-swift-sdk-search-search-submitted-parity-fixes

Conversation

@TarekAlQaddy

@TarekAlQaddy TarekAlQaddy commented Sep 30, 2026 •

Copy link
Copy Markdown

Similar to the Android SDK PR

Migrating the trackSearchSubmit method to the new v2 endpoint, migration is internal. Also adding section as a new parameter.
Couple of notes

  • Section now defaults to "Products" as we agreed. The events we get from customers will now include a section as a query param all the time
  • group name is silently ignored if set, the filters accepts group_id only. The name doesn't seem to exist in the new endpoint specs

@TarekAlQaddy
TarekAlQaddy requested review from a team and a balanced review from Copilot September 30, 2026 15:57
@TarekAlQaddy
TarekAlQaddy requested a review from a team as a code owner September 30, 2026 15:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The modified public method signature contradicts the stated internal-only migration and can break compatibility.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Migrates search-submit tracking to the v2 POST endpoint with JSON payloads and default section handling.

Changes:

  • Sends search data, group filters, and analytics tags in JSON.
  • Defaults the section to configured value or “Products.”
  • Updates request and worker tests for v2 behavior.
File Description
ConstructorIOTrackSearchSubmitTests.swift Tests v2 tracking behavior and payloads.
TrackSearchSubmitRequestBuilder.swift Tests POST request construction.
ConstructorIO.swift Adds section handling to search submission.
CIOTrackSearchSubmitData.swift Builds the v2 POST request.
Constants.swift Updates the endpoint path.

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

*/
public func trackSearchSubmit(searchTerm: String, originalQuery: String, group: CIOGroup? = nil, analyticsTags: [String: String]? = nil, completionHandler: TrackingCompletionHandler? = nil) {
let data = CIOTrackSearchSubmitData(searchTerm: searchTerm, originalQuery: originalQuery, group: group, analyticsTags: mergeAnalyticsTags(defaultAnalyticsTags: self.config.defaultAnalyticsTags, newAnalyticsTags: analyticsTags))
public func trackSearchSubmit(searchTerm: String, originalQuery: String, group: CIOGroup? = nil, analyticsTags: [String: String]? = nil, section: String? = nil, completionHandler: TrackingCompletionHandler? = nil) {

@TarekAlQaddy TarekAlQaddy Oct 1, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Normal calls to the method compile and work. Such as:

c.trackSearchSubmit(searchTerm: "a", originalQuery: "a")
c.trackSearchSubmit(searchTerm: "a", originalQuery: "a", group: 1)
c.trackSearchSubmit(searchTerm: "a", originalQuery: "a") { _ in }
c.trackSearchSubmit(searchTerm: "a", originalQuery: "a", group: 1, analyticsTags: nil, completionHandler: nil)

We introduced similar updates in the past and there weren't complains.
What doesn't work is calling the method by it's full name which is rare or not re-compiling the SDK after updating the version which is non realistic

constructor-claude-bedrock[bot]

This comment was marked as outdated.

@evanyan13
evanyan13 self-requested a review September 30, 2026 16:29
@TarekAlQaddy
TarekAlQaddy marked this pull request as draft October 1, 2026 11:48
@TarekAlQaddy
TarekAlQaddy marked this pull request as ready for review October 1, 2026 14:44
constructor-claude-bedrock[bot]

This comment was marked as outdated.

@evanyan13 evanyan13 changed the title Migrate to v2 search submit endpoint [CDX-566] Migrate to v2 search submit endpoint Oct 7, 2026
evanyan13

This comment was marked as outdated.

* Refactor trackSearchSubmit by creating an override

* Update trackSearchSubmit usage in project

* Rename struct and update tests

---------

Co-authored-by: Evan Yan <evan.yan@constructor.io>

@constructor-claude-bedrock constructor-claude-bedrock Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This PR migrates trackSearchSubmit to the v2 POST /v2/behavioral_action/search endpoint, introduces CIOTrackSearchSubmitRequest / CIOTrackSearchSubmitFilters as the new public API surface, deprecates the old parameter-based overload, and adds a section parameter — all well-executed with solid test coverage.

Inline comments: 6 discussions added

Overall Assessment: ⚠️ Needs Work

Comment thread AutocompleteClient/FW/Logic/Request/CIOTrackSearchSubmitData.swift
Comment thread AutocompleteClient/FW/Logic/Request/CIOTrackSearchSubmitData.swift
builder.build(trackData: tracker)
let payload = self.payload(builder.getRequest())

XCTAssertEqual(payload?["analytics_tags"] as? [String: String], [:], "Empty analytics tags should be sent as-is")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important Issue: The test testTrackSearchSubmitBuilder_WithEmptyAnalyticsTags asserts that an empty analytics tags dict ([:]) is serialised into the body. However, the implementation only adds analytics_tags when analyticsTags != nil — it does not check .isEmpty. An empty dict [:] is non-nil, so it will be sent to the endpoint. Verify with the backend team that sending "analytics_tags": {} is accepted. If the endpoint treats it the same as omitting the field, a consistency argument can be made either way, but the test expectation and the behaviour should at least match intentional design. If empty tags should be omitted (like nil), the fix is:

if let analyticsTags = self.analyticsTags, !analyticsTags.isEmpty {
    dict["analytics_tags"] = analyticsTags
}

This aligns with how other events in the SDK treat empty collections.

func testTrackSearchSubmit() {
let searchTerm = "corn"
let searchOriginalQuery = "corn"
private func stubCapturingPayload(_ builder: CIOBuilder, _ capture: @escaping ([String: Any]?) -> Void) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: stubCapturingPayload always stubs against searchSubmitURL (the Products section variant), which means any test that passes a different section (e.g. testTrackSearchSubmit_WithSection with "Search Suggestions") cannot use this helper and stubs manually. This is fine as-is, but a small overload taking an explicit URL string would remove the duplication in future tests:

private func stubCapturingPayload(_ builder: CIOBuilder, url: String? = nil, _ capture: @escaping ([String: Any]?) -> Void) {
    stub(regex(url ?? searchSubmitURL)) { ... }
}

Not a blocker, but would make the helper more reusable.

This branch has not been deployed

No deployments
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