Skip to content

feat: [SDK-5375] add sessions API client - #1763

Merged
fadi-george merged 2 commits into
new-session-eventsfrom
fadi/sdk-5375
Oct 9, 2026
Merged

fadi-george merged 2 commits into
new-session-eventsfrom
fadi/sdk-5375

Conversation

@fadi-george

@fadi-george fadi-george commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #1762 (SDK-5371). Merge that first; this PR's diff is only the sessions API client.

Description

One Line Summary

Add OSSessionsBackendService for POST /apps/{app_id}/sessions and PATCH /apps/{app_id}/sessions/{session_id}.

Details

Motivation

Typed request/response layer for the public sessions API, used by the upcoming persistent queue. Mirrors Android's SessionsBackendService (OneSignal/OneSignal-Android-SDK#2775).

Scope

  • New OSRequestCreateSession / OSRequestUpdateSession requests and OSSessionsBackendService in OneSignalOSCore.
  • Returns OSSessionsApiResult: success, retry(statusCode, retryAfterSeconds) for no response (code 0), 5xx, 408, 429, or a create success missing data.session_id, and drop(statusCode) for other 4xx or a request the client rejected before sending (-1, missing app ID).
  • Retry-After is read from the response headers (delay-seconds only). Falls back to 60s when unparsable or missing on a 429, matching Android.
  • A 2xx whose body fails to parse (which OneSignalClient reports as a failure) is retried for create and treated as success for update.
  • OSNetworkingUtils.getResponseStatusType is unchanged.
  • start_time / end_time are sent as RFC 3339 UTC strings with milliseconds (2023-11-14T22:13:20.000Z), per sessions-http/openapi.yaml.
  • All new types are internal to OneSignalOSCore.
  • No callers yet, no bulk endpoint. No behavior change.

Open questions

  • device_type is sent as 0 (iOS push). Please confirm against the agreed contract.
  • No JWT or subscription header, and 401/403 are drop. To revisit when the queue is wired.

Testing

Unit testing

OSSessionsBackendServiceTests: request bodies (with and without optional fields), 202 parsing, malformed create responses, retry vs drop classification, Retry-After propagation and fallback, RFC 3339 timestamps.

Manual testing

Not tested on device; no callers yet.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

🤖 Generated with Claude Code

@cursor cursor 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.

Multi-model review

Reviewed the new sessions API client against OneSignalClient (Claude Opus 5.5, GPT 5.6 Sol, Grok 4.7). The Android #2775 holes are already avoided here: offline is 0 (retried via <= 0), session_id rejects NSNull/non-strings/empty, and an unparsable 2xx is retry-on-create / success-on-update.

Act on (3/3): classifyFailure retries every code <= 0, but on this client -1 is only handleMissingAppIdError (empty/(null) segment after apps/). Transport failure is 0. An empty appId therefore retries forever; the test lists -1 as a network error. Drop -1, or reject an empty appId up front.

Consider (2/3): OneSignalClient.willReattemptRequest already retries 5xx and 0 up to four times without reading Retry-After before this layer sees the failure. A later caller retry restarts that inner loop.

Consider (2/3): No JWT / subscription-header hook, and 401/403 are drop. Confirm the sessions contract before wiring the queue.

Consider: request/result types are public in OSCore while OSFeatureFlagsBackendService is internal; the checklist says no public API change. Lone: other 2xx with a parsed body ignore error.response on create (Sol); update 404 is drop despite the post-create replication delay used elsewhere (Grok).

Noted: unencoded path segments (matches most backends); empty 200/201 body reported as 202; consent 0 retried (documented). Dismissed: Android Success("null"); unparsable-2xx-as-drop; top-level JSON array crash (pre-existing client).

Open in Web View Automation 

Sent by Cursor Automation: PR Reviews

Comment thread iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSSessionsBackendService.swift Outdated
@fadi-george
fadi-george added this pull request to stack #1765 October 7, 2026 23:41

@abdulraqeeb33 abdulraqeeb33 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.

One blocker: start_time and end_time go out as Int64 epoch seconds, but the contract (sessions-http/openapi.yaml) types both as RFC3339 date-time strings. Android hit the same thing on #2775. Please send ISO8601DateFormatter output in UTC with fractional seconds and update the test that asserts a number.

The failing CI test is a flake: 2b35f56 passed, and the test does not touch this code. Also, b2c0925 holds the #1762 review fixes, so it should live on that branch.

Comment thread iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSSessionsRequests.swift Outdated
@fadi-george

Copy link
Copy Markdown
Collaborator Author

Thanks. Timestamps are fixed in d7f7148. The #1762 review fixes are on fadi/sdk-5371 now (f9e6376), so this PR's diff is only the sessions client. I also made the new types internal, and noted the JWT and 401/403 question in the PR description for when we wire up the queue.

@abdulraqeeb33 abdulraqeeb33 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.

Timestamp blocker fixed in d7f7148: start_time and end_time are RFC3339 UTC strings with millis, and the tests assert them. Missing app id now drops. Rebase looks clean.

Non-blocking, for the queue PR:

  1. A create that keeps returning 2xx without session_id retries forever. The queue needs an attempt cap, same as Android #2777.
  2. OneSignalClient already reattempts 5xx and no-network internally, ignoring Retry-After, so an outage gets several fast hits per op before this backoff applies.

Base automatically changed from fadi/sdk-5371 to new-session-events October 9, 2026 19:15
fadi-george and others added 2 commits October 9, 2026 12:15
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… missing app ID

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fadi-george
fadi-george merged commit a555ef4 into new-session-events Oct 9, 2026
4 checks passed
@fadi-george
fadi-george deleted the fadi/sdk-5375 branch October 9, 2026 20:20
fadi-george added a commit that referenced this pull request Oct 9, 2026
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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