call(back)
Algorithms & Data StructuresmediumSign in to star problems

Voting System API

Design the APIs for a voting system, answering in code: a VotingService whose methods stand in for the endpoints and return HTTP-style status objects.

  • createPoll(pollId, options) → POST /polls. { status: 201, options } with the options sorted; { status: 409 } if the poll exists; { status: 422 } if the options are empty or repeat.
  • castVote(pollId, voter, option) → PUT /polls/{id}/votes/{voter} — a PUT, so a retried request cannot double-count. { status: 404 } for an unknown poll, { status: 409 } if it is closed, { status: 422 } for an unknown option, { status: 201, result: "recorded" } for a voter's first vote, { status: 200, result: "unchanged" } for the same vote again, { status: 200, result: "changed" } when the voter switches.
  • closePoll(pollId) → { status: 204 }, or { status: 404 }.
  • results(pollId) → { status: 200, results: [[option, count], ...] } for options with at least one vote, sorted by count descending then option ascending; { status: 404 } for an unknown poll. Results stay readable after the poll closes.
  • audit() → every successful mutation, in order: ["createPoll", pollId, options] (as requested), ["vote", pollId, voter, previousOption | null, option], ["closePoll", pollId].
svc.createPoll("p1", ["b", "a"])       ->  { status: 201, options: ["a", "b"] }
svc.castVote("p1", "v1", "a")         ->  { status: 201, result: "recorded" }
svc.castVote("p1", "v1", "a")         ->  { status: 200, result: "unchanged" }   // safe retry
svc.castVote("p1", "v1", "b")         ->  { status: 200, result: "changed" }
svc.results("p1")                     ->  { status: 200, results: [["b", 1]] }

Hints

Hint 1

Key the vote store by (pollId, voter). A cast looks up the previous option: none means recorded, the same means unchanged, different means changed — decrement the old tally and increment the new one so the read model stays consistent.

Hint 2

Keep the tally as its own structure updated on every write, so reads never rescan votes, and append one audit entry per successful mutation before returning.

Asked at