Skip to content

How-to: Emoji-Reaktions-API

FT-Referenz: FT306 (NENE2-FT/emojilog) — Emoji-Reaktionen: UNIQUE(post_id, user_id, emoji) erlaubt dasselbe Emoji von mehreren Benutzern, verhindert aber, dass ein Benutzer zweimal mit demselben Emoji reagiert, mb_strlen max 8 Zeichen, urldecode() für Emoji im DELETE-Pfad, user_reactions zeigt die Reaktionen des aktuellen Akteurs, Reaktionen geordnet nach Anzahl DESC, 18 Tests / 28 Assertions bestanden.

Diese Anleitung zeigt, wie ein Emoji-Reaktionssystem implementiert wird, bei dem mehrere Benutzer auf einen Beitrag mit beliebigen Emojis reagieren können, aber jeder Benutzer ein gegebenes Emoji nur einmal pro Beitrag verwenden kann.

Schema

sql
CREATE TABLE reactions (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    post_id    INTEGER NOT NULL,
    user_id    INTEGER NOT NULL,
    emoji      TEXT    NOT NULL,
    created_at TEXT    NOT NULL,
    UNIQUE (post_id, user_id, emoji),
    FOREIGN KEY (post_id) REFERENCES posts(id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

UNIQUE(post_id, user_id, emoji) erlaubt:

  • Gleiches Emoji von mehreren Benutzern: Alice und Bob können beide mit 👍 reagieren
  • Verschiedene Emojis vom gleichen Benutzer: Alice kann sowohl 👍 als auch ❤️ verwenden

Verhindert aber:

  • Gleicher Benutzer + gleiches Emoji zweimal: Alice kann 👍 auf demselben Beitrag nicht zweimal verwenden

Endpunkte

MethodePfadAuthBeschreibung
GET/posts/{id}/reactionsX-User-Id (optional)Reaktionszählungen + Reaktionen des Akteurs abrufen
POST/posts/{id}/reactionsX-User-IdReaktion hinzufügen
DELETE/posts/{id}/reactions/{emoji}X-User-IdReaktion entfernen

Reaktion hinzufügen — Strikte Validierung

php
if (!isset($body['emoji']) || !is_string($body['emoji']) || trim($body['emoji']) === '') {
    return $this->responseFactory->create(['error' => 'emoji is required'], 422);
}
$emoji = trim($body['emoji']);
if (mb_strlen($emoji) > 8) {
    return $this->responseFactory->create(['error' => 'emoji too long'], 422);
}

$added = $this->repository->addReaction($postId, $actorId, $emoji, date('c'));
if (!$added) {
    return $this->responseFactory->create(['error' => 'already reacted with this emoji'], 409);
}
  • is_string()-Prüfung lehnt Nicht-String-Typen ab
  • trim() vor Leer-Prüfung verhindert nur-Leerzeichen-Emoji
  • mb_strlen() — nicht strlen() — für korrekte Multibyte-Zeichenzählung
  • Doppeltes Hinzufügen → 409 Conflict (nicht 422)

Reaktion entfernen — URL-Decode für Emoji im Pfad

php
$emoji = isset($params['emoji']) && is_string($params['emoji']) ? urldecode($params['emoji']) : '';
if ($emoji === '') {
    return $this->responseFactory->create(['error' => 'invalid emoji'], 404);
}

Emoji-Zeichen in URL-Pfadsegmenten müssen von Clients URL-kodiert werden. urldecode() stellt das ursprüngliche Emoji für die DB-Suche wieder her. Beispiel: DELETE /posts/1/reactions/%F0%9F%91%8D → sucht 👍.

Reaktionszählungs-Antwort

php
// Nach Emoji gruppieren, zählen, nach Anzahl DESC ordnen
$counts = $this->repository->getReactionCounts($postId);

// Wenn Akteur angegeben, anzeigen, welche Emojis er verwendet hat
$userReactions = [];
if ($actorId !== null) {
    $userReactions = $this->repository->getUserReactions($postId, $actorId);
}

return $this->responseFactory->create([
    'post_id'        => $postId,
    'reactions'      => $counts,        // [{emoji, count}, ...] geordnet nach Anzahl DESC
    'user_reactions' => $userReactions, // ['👍', '❤️', ...] für den aktuellen Akteur
]);

user_reactions ist leer, wenn kein X-User-Id-Header angegeben wird — dieses Feld zeigt die Reaktionen des aktuellen Betrachters, um Frontends dabei zu helfen, aktive Reaktionen hervorzuheben.


Was man NICHT tun sollte

Anti-MusterRisiko
UNIQUE(post_id, user_id) (keine Emoji-Spalte)Ein Benutzer kann pro Beitrag immer nur ein Emoji verwenden
strlen() für Emoji-LängenprüfungMulti-Byte-Emoji wie 🎉 (4 Bytes) würden falsch gezählt
Kein urldecode() für Pfad-Emoji👍 als %F0%9F%91%8D stimmt nie mit gespeichertem 👍 überein
404 bei doppelter Reaktion zurückgebenVerbirgt die 409-Semantik — doppelte Reaktionen sind Konflikte, keine fehlenden Ressourcen
Kein Emoji-LängenlimitBeliebig lange Strings werden als Emoji-Spalte gespeichert
Leere user_reactions bei keinem Akteur, aber Schlüssel trotzdem einschließenWeglassen oder [] zurückgeben — beides ist in Ordnung, aber Verhalten dokumentieren
trim() nach Leer-PrüfungNur-Leerzeichen-" " Emoji passiert als gültig

Veröffentlicht unter der MIT-Lizenz.