Sitelet https://github.com/GetStream/stream-chat-android/pull/6733
Skip to content

Migrate the thread reply and pinned message responses to the generated MessageResponse - #6733

Merged
gpunto merged 5 commits into
developfrom
migrate/message-response
Sep 28, 2026
Merged

gpunto merged 5 commits into
developfrom
migrate/message-response

Conversation

@gpunto

@gpunto gpunto commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Goal

Parse the messages returned by the thread replies and pinned messages endpoints with the generated
MessageResponse.

Part of AND-1291

Implementation

  • Point MessagesResponse.messages at the generated MessageResponse and map it with a new
    MessageResponse.toDomain(), alongside the existing DownstreamMessageDto mapper, which every other
    endpoint still uses.
  • Vendor MessageResponse and the models only it needs: DraftResponse, ReminderResponseData and
    SharedLocationResponseData, each with its own mapper.
  • MessageResponseAdapter collects the flattened custom data. Keys the generated model now declares
    (mml, poll_id, restricted_visibility, mentioned_group_ids, image_labels, draft) stay in
    extraData as well, as they were before.
  • V1 moderation_details is not declared on the payload and arrives as custom data, so it is read from
    there into moderationDetails and removed from extraData.
  • A null entry in mentioned_channel_members is skipped instead of throwing.

Testing

Mutation sweep over the new mappers: zero survivors.

MessageResponseParityTest parses every message fixture through both the hand-written DTO and the
generated model and requires the same Message, field by field. Where a fixture was leaner than the wire,
it only fills fields the backend always sends.

Device-probed a thread reply with a mention, a custom attachment, a quote, a reaction, a reminder and custom
data, and a pinned parent and a pinned static location. Every field matched getMessage, which still parses
the hand-written DTO. The differences were what the endpoints send: neither endpoint sends the message's
channel, and pinned messages come back without shared_location, thread_participants or poll. That last
one is the same on develop.

A second probe put unusual messages in a thread and in the pinned list: a soft-deleted reply, a link
preview, silent and shown-in-channel replies, an image attachment, a quote of a deleted message, a
translation, a giphy, a poll and an expiring pin. Both endpoints parsed them all, and each matched
getMessage apart from the endpoint differences above.

The generated model requires some fields the hand-written DTO did not, so a missing one would fail the whole
response. Every required field across the models these responses reach is a plain, always-sent tag on the
backend, including the placeholder user sent for a deleted author, which a new parity fixture covers.

Summary by CodeRabbit

  • Improvements
    • Message data now better preserves details such as polls, reminders, shared locations, reactions, and quoted messages when received from the service.
    • Custom message fields and moderation details are handled more consistently.
    • Poll update times now reflect the latest available update.
  • Bug Fixes
    • Improved handling of missing message collections and channel information to support more reliable message display.

@gpunto gpunto added the pr:internal Internal changes / housekeeping label Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 6.09 MB 6.11 MB 0.02 MB 🟢
stream-chat-android-ui-components 11.39 MB 11.41 MB 0.02 MB 🟢
stream-chat-android-compose 13.07 MB 13.09 MB 0.02 MB 🟢

@gpunto
gpunto marked this pull request as ready for review September 28, 2026 13:52
@gpunto
gpunto requested a review from a team as a code owner September 28, 2026 13:52

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

Looks good. One question inline, not blocking.

@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 7b321ba9-916b-483e-9acc-db7b160065f2

📥 Commits

Reviewing files that changed from the base of the PR and between 44b665f and 9015c21.

📒 Files selected for processing (13)
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DomainMapping.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/MessagesResponse.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/MoshiChatParser.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/adapters/MessageResponseAdapter.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/DraftResponse.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/MessageResponse.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/ReminderResponseData.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/SharedLocationResponseData.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/MoshiChatApiTestArguments.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/mapping/DomainMappingTest.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/MessageResponseParityTest.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/MessageResponseParsingTest.kt

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.


Walkthrough

API2 message responses now use network response models. The parser reads these models, and domain mapping converts message, reminder, and shared-location response data into domain objects. Tests cover parsing, mapping, and parity with the existing DTO path.

Changes

Message response integration

Layer / File(s) Summary
Response models and parser
stream-chat-android-client/src/main/java/io/getstream/chat/android/network/models/*, stream-chat-android-client/src/main/java/io/getstream/chat/android/client/parser2/*, stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/response/MessagesResponse.kt
Added Moshi models for messages, drafts, reminders, and shared locations. Registered the message response adapter and changed MessagesResponse.messages to use MessageResponse.
Response-to-domain mapping
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DomainMapping.kt
Added mappings for messages, reminders, and shared locations. Message mapping handles moderation details, defaults, nested data, and poll update times.
Parsing and mapping validation
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/api2/*, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/*
Added response fixtures and tests for parsing, DTO parity, and domain mapping.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Refactor

Suggested reviewers: velikovpetar

Merge Risk: ⚪ Minimal · up to 9015c

The migrated replies and pinned-message paths have no established blocking issue and are ready for normal merge checks.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 9015c

Replies and pinned messages now carry visibility metadata into message state where the previous parsing path did not. The change warrants checking whether clients can supply that metadata and how the server validates it; an exploit has not been established.

Retained concerns

  • Medium · security · inferred: Replies and pinned messages now promote restricted_visibility from response JSON into persistent domain visibility metadata. If sender-controlled custom data can use that reserved name, the client may treat it as typed visibility state; backend validation and the resulting security effect remain unverified.
Security review details

Security Blast Radius

  • inferred — The changed parsing boundary reaches reply and pinned-message consumers within the client. The available evidence does not show a new service, tenant, credential, or infrastructure boundary.

Security Findings and Attack Paths

  • inferred — A sender who can place restricted_visibility in a returned message could influence typed client visibility state. Whether senders can supply that reserved field, or whether its propagation changes enforcement, is unknown; this is not a verified attack path.

Trust Boundaries and Controls

  • observed — Retaining restricted_visibility in custom data does not prevent the generated model from also parsing it as a typed field. The earlier DTO conversion did not populate the corresponding domain field.

Hardening Proposals

  • proposed — Establish whether the server reserves and validates restricted_visibility, and whether client consumers treat the response value as display metadata or an authorization decision before relying on the new typed mapping.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.21% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 39 functions across 13 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: migrating thread reply and pinned message responses to the generated MessageResponse.
Description check ✅ Passed The description includes complete Goal, Implementation, and Testing sections. It explains the migration, implementation details, compatibility behavior, and validation results. UI and checklist sectio…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks each message field,
And hops where parsed responses yield.
A poll time joins the mapped reply,
While shared locations pass nearby.
The tests keep watch as models fly.

Comment @coderabbitai help to get the list of available commands.

@gpunto
gpunto enabled auto-merge September 28, 2026 15:22
@sonarqubecloud

Copy link
Copy Markdown

@gpunto
gpunto added this pull request to the merge queue Sep 28, 2026
Merged via the queue into develop with commit 1936608 Sep 28, 2026
19 checks passed
@gpunto
gpunto deleted the migrate/message-response branch September 28, 2026 16:47
@stream-public-bot stream-public-bot added the released Included in a release label Sep 30, 2026
@stream-public-bot

Copy link
Copy Markdown
Contributor

🚀 Available in v7.13.0

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

Labels

pr:internal Internal changes / housekeeping released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants