Chat — Serializers¶
Overview¶
The serializer layer in the chat app defines the API contract between backend and frontend.
It is responsible for:
- validating request payloads
- shaping response payloads
- exposing frontend-friendly message, conversation, participant, and attachment data
- keeping transport concerns separate from chat workflow logic
The serializer layer should remain thin.
Business logic such as:
- creating conversations
- sending messages
- attaching uploaded files
- enforcing participant rules
- marking conversations as read
- sending notifications
- websocket broadcasting
belongs in services and consumers, not in serializers.
Serializer structure¶
The chat app serializer layer is split into focused modules:
serializers/attachments.pyserializers/conversations.pyserializers/messages.pyserializers/participants.py
This makes the API surface easier to understand and maintain.
Attachments serializers¶
MessageAttachmentSerializer¶
Represents an attachment in API responses.
Purpose¶
This serializer gives the frontend all metadata needed to display or download an uploaded attachment.
Fields¶
idconversation_idmessage_iduploaded_by_idfilenamecontent_typesize_bytesurlcreated_at
Notes¶
message_idmay be null if the file has been uploaded but not yet attached to a messageurlis derived from the file storage backend- the serializer supports both:
- already-linked attachments
- orphan uploads waiting to be attached
Participants serializers¶
ParticipantSerializer¶
Represents a participant in a conversation.
Purpose¶
This serializer is used to show who is currently part of a conversation and what their read state looks like.
Fields¶
idconversationuser_idusernamedisplay_nameroleis_activelast_read_atjoined_at
Notes¶
The serializer enriches participant data with:
usernamedisplay_name
so the frontend does not need to make extra user lookups for common display cases.
AddParticipantSerializer¶
Validates requests to add or reactivate a participant.
Fields¶
user_idrole
Purpose¶
This serializer validates the request body for participant addition.
It does not decide whether the user may actually be added.
That belongs in services.
RemoveParticipantSerializer¶
Validates participant removal payloads if needed.
Fields¶
user_id
Purpose¶
This serializer is a small transport helper for remove-style operations.
Depending on route design, the user_id may also come from the URL rather than request body.
Messages serializers¶
MessageSerializer¶
Represents a chat message in API responses.
This is one of the most important serializers in the app.
Purpose¶
It provides a frontend-ready message payload for:
- REST history endpoints
- edit/delete responses
- future websocket alignment
Fields¶
idconversation_idsender_idsender_usernamesender_display_namebodydataattachmentscreated_atedited_atdeleted_at
Notes¶
This serializer includes nested attachments so the frontend can render complete message rows without separately fetching files.
It also enriches sender information for display.
This is especially important for web and mobile chat UIs.
MessageCreateSerializer¶
Validates input for message creation.
Fields¶
bodydataattachment_ids
Validation rules¶
A message must include at least one of:
- non-empty body
- one or more attachments
This allows:
- normal text messages
- attachment-only messages
- mixed text + attachment messages
Notes¶
This serializer is especially important for a frontend-friendly upload flow:
- upload file
- get attachment ID
- send message with
attachment_ids
MessageEditSerializer¶
Validates input for editing an existing message.
Fields¶
body
Purpose¶
Used by edit endpoints to validate the new message body.
Authorization is not handled here.
That belongs in services.
MessageListResponseSerializer¶
Defines the paginated message-history response shape.
Fields¶
itemsnext_before
Purpose¶
This serializer reflects the chat history pagination contract.
The response shape supports cursor-style pagination using a timestamp boundary.
Notes¶
next_before is used by the frontend to request older messages.
Conversations serializers¶
ConversationSerializer¶
Represents the base conversation model.
Fields¶
idinternal_orgcustomer_orgtitletopic_typetopic_idcreated_atclosed_at
Purpose¶
This serializer is suitable for:
- simple detail responses
- create responses
- internal transport use
ConversationListSerializer¶
Represents a frontend-friendly conversation list item.
Fields¶
idinternal_orgcustomer_orgtitletopic_typetopic_idcreated_atclosed_atunread_countparticipant_countlast_message
Purpose¶
This serializer is used for conversation lists where the frontend needs summary data.
Notes¶
It extends the raw conversation model with read-model fields such as:
- unread count
- participant count
- last message preview
This makes it much more useful for mobile and web chat sidebars or inbox views.
ConversationCreateSerializer¶
Validates conversation creation payloads.
Fields¶
customer_org_idtitletopic_typetopic_id
Purpose¶
Used when creating a new conversation from the internal side.
Notes¶
This serializer validates payload shape only.
It does not decide:
- whether the customer org is linked
- whether the actor may create the conversation
That belongs in services.
Serializer responsibilities by layer¶
Serializer layer¶
Responsible for:
- validating payload shape
- normalizing request data
- exposing stable frontend-facing response structures
- adding lightweight display-oriented enrichment
Service layer¶
Responsible for:
- creating conversations
- sending messages
- attaching files
- checking permissions
- handling participant membership
- computing unread counts
- marking read state
View layer¶
Responsible for:
- receiving HTTP requests
- invoking serializers
- calling services
- returning HTTP responses
Consumer layer¶
Responsible for:
- websocket message handling
- websocket event broadcasting
- real-time delivery
Read-model enrichment¶
The chat serializers include frontend-focused convenience fields.
These are not business rules.
They are response-shaping features.
Message enrichment¶
MessageSerializer includes:
- sender username
- sender display name
- nested attachments
This makes the message payload much easier for frontend rendering.
Participant enrichment¶
ParticipantSerializer includes:
- display_name
- username
This avoids extra lookups for participant chips or presence lists.
Conversation enrichment¶
ConversationListSerializer includes:
- unread_count
- participant_count
- last_message
This gives the frontend the data needed to render a proper conversation list.
Data flow¶
flowchart TD
A[HTTP request] --> B[Serializer validation]
B --> C[View]
C --> D[Service layer]
D --> E[Models]
E --> F[Serializer output]
F --> G[HTTP response]
¶
flowchart TD
A[HTTP request] --> B[Serializer validation]
B --> C[View]
C --> D[Service layer]
D --> E[Models]
E --> F[Serializer output]
F --> G[HTTP response]
Message creation flow¶
flowchart TD
A[Client sends message payload] --> B[MessageCreateSerializer]
B --> C[Validate body or attachments]
C --> D[View calls message service]
D --> E[Message persisted]
E --> F[Response shaped with MessageSerializer]
Attachment upload flow¶
flowchart TD
A[Client uploads file] --> B[Upload view]
B --> C[Attachment service]
C --> D[MessageAttachment created]
D --> E[MessageAttachmentSerializer]
E --> F[Attachment metadata returned]
¶
flowchart TD
A[Client uploads file] --> B[Upload view]
B --> C[Attachment service]
C --> D[MessageAttachment created]
D --> E[MessageAttachmentSerializer]
E --> F[Attachment metadata returned]Conversation list flow¶
flowchart TD
A[List conversations request] --> B[Conversation service]
B --> C[Attach unread and last_message data]
C --> D[ConversationListSerializer]
D --> E[Frontend-ready conversation list response]
Frontend readiness benefits¶
The serializer split makes the chat backend much easier to integrate into web and mobile clients.
It gives the frontend: - clear message payloads - nested attachment data - participant display metadata - conversation summary data - stable pagination response shapes
This reduces the need for frontend-side stitching or extra requests.
What serializers do not do¶
These serializers do not: - check whether the requester is a participant - decide who can edit/delete messages - attach uploaded files to messages - calculate unread counts themselves - create notifications - broadcast websocket events - enforce org link rules
Those responsibilities belong to: - services - views - consumers
Design principles¶
Thin serializers¶
Serializers should validate and shape data, not run workflow logic.
Frontend-friendly payloads¶
Responses should be ready to render in chat UIs with minimal extra processing.
Stable message shape¶
The same message structure should ideally be shared across: - REST history - REST action responses - websocket events
Focused modules¶
Splitting serializers by domain keeps the chat API easier to evolve.
Best practices¶
- keep request validation separate from service decisions
- use read serializers for frontend-facing payloads
- use dedicated write serializers for create/edit actions
- include nested attachments where message rendering needs them
- keep serializer-enriched fields lightweight
- avoid embedding permission logic in serializers
Future extensions¶
Possible future serializer improvements include: - separate detail vs list serializers for conversations - message reaction serializers - read receipt serializers - richer participant presence serializers - system message serializers - message type-specific serializers for structured content - websocket event serializers matching REST serializers exactly
Summary¶
The chat serializer layer provides the API-facing structure for: - attachment metadata - participant data - message payloads - paginated history responses - conversation list items - conversation creation input
It ensures the chat API is: - structured - frontend-friendly - easy to evolve - clearly separated from business workflow logic