Live Stream ban — RTK Query
Yayın ban mobil API entegrasyonu
Live Stream Ban - React Native (RTK Query)
Migration rehberi
Yapılandırma sırası için Migration şablonu. Yeni düzenlemelerde Amaç → Önkoşullar → Endpoint → Request/Response → Hata kodları → Client adımları → İlgili sayfalar bölümlerini tercih edin.
Bu doküman, live-stream-ban modülü endpointlerini React Native tarafında RTK Query ile kullanmak için hazırlandı.
Kapsam
- Base path:
/api/v1/live-stream-ban - Auth:
Authorization: Bearer <JWT>(tüm endpointlerde zorunlu) - Response formati:
BaseResponseDto<T>(asil payloaddataalanindadir) - Ban modeli: sadece stream bazli
- Unban: fiziksel silme değil, soft delete (
DELETE /:id)
Is Kurallari (Mobil Tarafindan Bilinmeli)
- Ban oluşturma ve ban kaldirma sadece ilgili stream creator tarafından yapilabilir.
- Ayni
targetUserId + liveStreamIdiçin aktif duplicate ban olusturulamaz. checkendpointindeliveStreamIdquery parametresi zorunludur.actionTypealanini göndermezseniz backend default olarakBLOCKkullanir.
Endpoint Ozeti
POST /api/v1/live-stream-banGET /api/v1/live-stream-banGET /api/v1/live-stream-ban/:idGET /api/v1/live-stream-ban/check/:targetUserId?liveStreamId=...DELETE /api/v1/live-stream-ban/:id
Socket Baglantisi (Ban Eventleri)
REST cagrilarina ek olarak ban/unban olaylari socket ile de yayinlanir.
- Namespace:
/live-stream - Oda:
stream:<liveStreamId> - Odaya giris:
joinStreameventi ile{ streamId }gönderilmelidir.
Ban endpointleri tetiklenince gateway su eventleri yayinlar:
userBanneduserBanRevoked
userBanned payload:
{
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"targetUser": {
"_id": "673ac9e2c93fe18d3fdd23f1",
"username": "target-user"
},
"actionType": "BLOCK",
"reason": "Spam",
"timestamp": "2026-03-09T12:10:00.000Z"
}userBanRevoked payload:
{
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"timestamp": "2026-03-09T12:20:00.000Z"
}React Native socket ornegi (socket.io-client):
import { io, Socket } from 'socket.io-client';
type UserBannedEvent = {
targetUserId: string;
targetUser?: {
_id: string;
username?: string;
name?: string;
surname?: string;
profilePhoto?: string | null;
};
actionType: 'BLOCK' | 'CHAT_ONLY';
reason?: string;
timestamp: string;
};
type UserBanRevokedEvent = {
targetUserId: string;
timestamp: string;
};
export const connectLiveStreamSocket = ({
baseUrl,
accessToken,
streamId,
onUserBanned,
onUserBanRevoked,
}: {
baseUrl: string;
accessToken: string;
streamId: string;
onUserBanned: (payload: UserBannedEvent) => void;
onUserBanRevoked: (payload: UserBanRevokedEvent) => void;
}) => {
const socket: Socket = io(`${baseUrl.replace(/\/$/, '')}/live-stream`, {
transports: ['websocket'],
auth: { token: accessToken },
});
socket.on('connect', () => {
socket.emit('joinStream', { streamId });
});
socket.on('userBanned', onUserBanned);
socket.on('userBanRevoked', onUserBanRevoked);
socket.on('disconnect', () => {
// reconnect stratejisi app seviyesinde ele alınabilir
});
return () => {
socket.emit('leaveStream', { streamId });
socket.off('userBanned', onUserBanned);
socket.off('userBanRevoked', onUserBanRevoked);
socket.disconnect();
};
};Not:
- Socket token'i
auth.tokenile göndermek en guvenli yoldur. - Ban eventleri sadece ilgili stream odasina (
stream:<id>) yayinlandigi içinjoinStreamçağrısı zorunludur. - UI tarafında
userBannedgeldiginde mesaj girisi/superlike butonu kapatilabilir.
Request / Response Sozlesmesi
1) Ban oluşturma
POST /api/v1/live-stream-ban
Body:
{
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"liveStreamId": "673acae0c93fe18d3fdd2407",
"actionType": "BLOCK",
"reason": "Toksik davranis"
}actionType: BLOCK | CHAT_ONLY (opsiyonel)
Response data (StreamBanResponseDto):
{
"_id": "67ca1234c93fe18d3fdd1234",
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"targetUser": {
"_id": "673ac9e2c93fe18d3fdd23f1",
"name": "Ayse",
"surname": "Yilmaz",
"profilePhoto": {
"_id": "67ca5555c93fe18d3fdd9999",
"url": "https://cdn.example.com/profile/ayse.webp"
}
},
"liveStreamId": "673acae0c93fe18d3fdd2407",
"actionType": "BLOCK",
"reason": "Toksik davranis",
"createdBy": "673ac9e2c93fe18d3fdd23f1",
"deletedAt": null,
"deletedBy": null,
"createdAt": "2026-03-09T12:00:00.000Z",
"updatedAt": "2026-03-09T12:00:00.000Z"
}2) Ban listesi
GET /api/v1/live-stream-ban
Query (hepsi opsiyonel):
page(default: 1)limit(default: 10, max: 100)targetUserIdliveStreamIdactionType(BLOCK | CHAT_ONLY)
Response data:
{
"list": [
{
"_id": "67ca1234c93fe18d3fdd1234",
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"targetUser": {
"_id": "673ac9e2c93fe18d3fdd23f1",
"name": "Ayse",
"surname": "Yilmaz",
"profilePhoto": {
"_id": "67ca5555c93fe18d3fdd9999",
"url": "https://cdn.example.com/profile/ayse.webp"
}
},
"liveStreamId": "673acae0c93fe18d3fdd2407",
"actionType": "BLOCK",
"reason": "Toksik davranis",
"createdBy": "673ac9e2c93fe18d3fdd23f1",
"deletedAt": null,
"deletedBy": null,
"createdAt": "2026-03-09T12:00:00.000Z",
"updatedAt": "2026-03-09T12:00:00.000Z"
}
],
"pagination": {
"currentPage": 1,
"totalPages": 1,
"totalItems": 1,
"itemsPerPage": 10,
"hasNextPage": false,
"hasPrevPage": false
}
}3) Tek ban detayi
GET /api/v1/live-stream-ban/:id
Response data: StreamBanResponseDto
4) Ban durum kontrolu
GET /api/v1/live-stream-ban/check/:targetUserId?liveStreamId=<streamId>
Response data:
{
"isBanned": true,
"ban": {
"_id": "67ca1234c93fe18d3fdd1234",
"targetUserId": "673ac9e2c93fe18d3fdd23f1",
"targetUser": {
"_id": "673ac9e2c93fe18d3fdd23f1",
"name": "Ayse",
"surname": "Yilmaz",
"profilePhoto": {
"_id": "67ca5555c93fe18d3fdd9999",
"url": "https://cdn.example.com/profile/ayse.webp"
}
},
"liveStreamId": "673acae0c93fe18d3fdd2407",
"actionType": "CHAT_ONLY",
"reason": "Spam",
"createdBy": "673ac9e2c93fe18d3fdd23f1",
"deletedAt": null,
"deletedBy": null,
"createdAt": "2026-03-09T12:00:00.000Z",
"updatedAt": "2026-03-09T12:00:00.000Z"
}
}Ban yoksa:
{
"isBanned": false,
"ban": null
}5) Ban kaldirma (soft delete)
DELETE /api/v1/live-stream-ban/:id
Response data: StreamBanResponseDto (deletedAt ve deletedBy dolu gelir)
RTK Query - Ornek API Slice
import { baseApi } from './baseApi';
type BaseResponseDto<T> = {
isSuccess: boolean;
statusCode: number;
data: T;
errors?: string[];
timestamp: string;
};
type BanActionType = 'BLOCK' | 'CHAT_ONLY';
type UserSummary = {
_id: string;
username?: string;
name?: string | null;
surname?: string | null;
profilePhoto?: {
_id: string;
url?: string;
} | null;
};
type Pagination = {
currentPage: number;
totalPages: number;
totalItems: number;
itemsPerPage: number;
hasNextPage?: boolean;
hasPrevPage?: boolean;
};
export type StreamBanResponse = {
_id: string;
targetUserId: string;
targetUser?: UserSummary | null;
liveStreamId: string;
actionType: BanActionType;
reason?: string | null;
createdBy: string;
deletedAt?: string | null;
deletedBy?: string | null;
createdAt?: string;
updatedAt?: string;
};
// Not: Backend kullanıcı ozetini cozemiyorsa `targetUser` null donebilir.
export type StreamBanListResponse = {
list: StreamBanResponse[];
pagination: Pagination;
};
export type CheckBanStatusResponse = {
isBanned: boolean;
ban: StreamBanResponse | null;
};
export type CreateLiveStreamBanBody = {
targetUserId: string;
liveStreamId: string;
actionType?: BanActionType;
reason?: string;
};
export type GetLiveStreamBansQuery = {
page?: number;
limit?: number;
targetUserId?: string;
liveStreamId?: string;
actionType?: BanActionType;
};
const unwrap = <T>(r: BaseResponseDto<T> | T): T => {
if (r && typeof r === 'object' && 'data' in (r as any)) {
return (r as BaseResponseDto<T>).data;
}
return r as T;
};
export const liveStreamBanApi = baseApi
.enhanceEndpoints({ addTagTypes: ['LiveStreamBan', 'LiveStreamBanCheck'] })
.injectEndpoints({
endpoints: (builder) => ({
createLiveStreamBan: builder.mutation<
StreamBanResponse,
CreateLiveStreamBanBody
>({
query: (body) => ({
url: '/v1/live-stream-ban',
method: 'POST',
body,
}),
transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
unwrap(r),
invalidatesTags: (_res, _err, arg) => [
{ type: 'LiveStreamBan', id: 'LIST' },
{ type: 'LiveStreamBanCheck', id: `${arg.targetUserId}-${arg.liveStreamId}` },
],
}),
getLiveStreamBans: builder.query<
StreamBanListResponse,
GetLiveStreamBansQuery | void
>({
query: (params) => ({
url: '/v1/live-stream-ban',
params,
}),
transformResponse: (r: BaseResponseDto<StreamBanListResponse> | StreamBanListResponse) =>
unwrap(r),
providesTags: (res) => {
const base = [{ type: 'LiveStreamBan' as const, id: 'LIST' }];
if (!res?.list?.length) {
return base;
}
return [
...base,
...res.list.map((item) => ({ type: 'LiveStreamBan' as const, id: item._id })),
];
},
}),
getLiveStreamBanById: builder.query<StreamBanResponse, { id: string }>({
query: ({ id }) => ({ url: `/v1/live-stream-ban/${id}` }),
transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
unwrap(r),
providesTags: (_res, _err, arg) => [{ type: 'LiveStreamBan', id: arg.id }],
}),
checkLiveStreamBanStatus: builder.query<
CheckBanStatusResponse,
{ targetUserId: string; liveStreamId: string }
>({
query: ({ targetUserId, liveStreamId }) => ({
url: `/v1/live-stream-ban/check/${targetUserId}`,
params: { liveStreamId },
}),
transformResponse: (
r: BaseResponseDto<CheckBanStatusResponse> | CheckBanStatusResponse,
) => unwrap(r),
providesTags: (_res, _err, arg) => [
{ type: 'LiveStreamBanCheck', id: `${arg.targetUserId}-${arg.liveStreamId}` },
],
}),
deleteLiveStreamBan: builder.mutation<StreamBanResponse, { id: string }>({
query: ({ id }) => ({
url: `/v1/live-stream-ban/${id}`,
method: 'DELETE',
}),
transformResponse: (r: BaseResponseDto<StreamBanResponse> | StreamBanResponse) =>
unwrap(r),
invalidatesTags: (_res, _err, arg) => [
{ type: 'LiveStreamBan', id: 'LIST' },
{ type: 'LiveStreamBan', id: arg.id },
],
}),
}),
});
export const {
useCreateLiveStreamBanMutation,
useGetLiveStreamBansQuery,
useGetLiveStreamBanByIdQuery,
useCheckLiveStreamBanStatusQuery,
useDeleteLiveStreamBanMutation,
} = liveStreamBanApi;React Native Kullanim Ornekleri
1) Bir kullanıcıyi banla
const [createBan, { isLoading: isBanning }] = useCreateLiveStreamBanMutation();
await createBan({
targetUserId,
liveStreamId,
actionType: 'BLOCK',
reason: 'Spam mesaj',
}).unwrap();2) Stream için ban listesi çek
const { data, isFetching, refetch } = useGetLiveStreamBansQuery({
liveStreamId,
page: 1,
limit: 20,
});
const bans = data?.list ?? [];3) Kullanıcı banli mi kontrol et
const { data: banStatus } = useCheckLiveStreamBanStatusQuery(
{ targetUserId, liveStreamId },
{ skip: !targetUserId || !liveStreamId },
);
if (banStatus?.isBanned) {
// chat input disable vb.
}4) Ban kaldir
const [deleteBan, { isLoading: isRemoving }] = useDeleteLiveStreamBanMutation();
await deleteBan({ id: banId }).unwrap();Error Handling Notlari
403: stream creator olmayan kullanıcı ban ekleyemez/kaldiramaz.404: ban veya stream bulunamadi.409: aktif duplicate ban oluşturma denemesi veya zaten kaldirilmis ban.- Validation hatalari (
400) için backenderrors/messagealanlarini UI'da toast/snackbar ile gösterebilirsiniz.
Onerilen UI Akisi
- Stream admin ekraninda once
getLiveStreamBans(liveStreamId)ile listeyi çekin. - Kullanıcı satirinda
Banaksiyonu ->createLiveStreamBan. - Ban kartinda
Kaldiraksiyonu ->deleteLiveStreamBan. - Mesaj gönderme gibi kritik aksiyonlardan once
checkLiveStreamBanStatusile gate kontrolu yapin.