Choose REST for a small, concrete interview contract. GraphQL is also reasonable when several clients need different projections, but the transport choice does not remove pagination or consistency decisions. Identity comes from the authenticated session; a request body cannot select another user's identity. Bound page sizes and validate every returned entity before merging it.
{
"snapshotId": "s17",
"orderedIds": ["p81"],
"nextCursor": "opaque-next-page-token",
"posts": [
{
"id": "p81",
"authorId": "u4",
"text": "Our community garden is open this weekend.",
"mediaIds": [],
"createdAt": "2026-10-03T08:00:00Z",
"revision": 3,
"likeCount": 12,
"viewerHasLiked": false
}
],
"users": [
{ "id": "u4", "displayName": "Mira", "avatarUrl": null }
],
"media": []
}
Define errors as part of the contract: expired authentication, validation failure, forbidden action, missing post, expired feed snapshot, and temporary service failure should produce different recovery options. For publishing, retain the same operation key after a lost response; generating a new key on Retry can create a second post. The server must scope keys to an account and operation, reject mismatched payload reuse, and document how long results are retained.