Skip to content

Enhancement: Harden API Surface (Validation, Rate Limiting, Problem Details) #11

@webreidi

Description

@webreidi

Goal

Increase robustness and security posture of the public API by adding strict validation, standardized error responses (RFC7807 ProblemDetails), and rate limiting to mitigate brute force or abusive traffic.

Motivation

  • Prevent invalid or brute force guess submissions (enumerating target words rapidly)
  • Provide consistent, machine-readable error responses
  • Lay foundation for future auth / multi-tenant concerns

Scope

Apply to all gameplay endpoints (create game, submit guess, get status).

Features

  1. Input Validation
    • Guess: exact expected length (configurable, default 5), alphabetic only A-Z, uppercase normalization
    • Reject duplicate guess within same session (409 Conflict)
    • Enforce max attempts (409 Conflict if exceeded)
  2. Rate Limiting
    • Use ASP.NET Core rate limiting middleware (.NET 8+/9) with policies:
      • Global: 60 requests / minute / IP
      • Guess submissions: 15 per minute per IP (named policy)
    • Return 429 with Retry-After header
  3. ProblemDetails Standardization
    • Global exception handler mapping domain exceptions: Validation -> 400, DuplicateGuess -> 409, MaxAttemptsExceeded -> 409, GameNotFound -> 404
    • Include: type, title, detail, status, extensions (gameId, code)
  4. Security / Hardening
    • Never return target word until completion (mask or omit)
    • Add X-Game-Id response header where relevant
    • Optional: tighten CORS to configured frontend origin(s)
  5. Logging Alignment

Implementation Plan

  1. Define / refine domain exception classes (DuplicateGuessException, MaxAttemptsExceededException, GameNotFoundException, ValidationException)
  2. Add minimal validation layer (either FluentValidation or manual guards in an input validator service)
  3. Configure app.UseExceptionHandler with custom ProblemDetails factory
  4. Add rate limiting: builder.Services.AddRateLimiter(...) and decorate endpoints with .RequireRateLimiting("guesses")
  5. Normalize guess input (trim + uppercase) before domain call
  6. Ensure target word not serialized pre-completion
  7. Add middleware / endpoint filter that injects X-Game-Id where a game context exists
  8. Add unit tests for validation paths (invalid length, invalid chars, duplicate, max attempts)
  9. Add functional test for rate limiting (hit limit + assert 429 + Retry-After)
  10. Update README with error contract examples (sample ProblemDetails payloads)

Acceptance Criteria

  • Invalid guess -> 400 ProblemDetails JSON
  • Duplicate guess -> 409 ProblemDetails
  • Exceeded attempts -> 409 ProblemDetails
  • Unknown game id -> 404 ProblemDetails
  • Rate limit exceeded -> 429 w/ Retry-After
  • Valid flow unchanged for UI

Non-Goals

  • Authentication
  • Distributed rate limiting (in-memory acceptable initial)

Risks & Mitigations

  • Overly strict rate limit: make values configurable via RateLimiting:*
  • Noise in logs: ensure validation logs are concise

Definition of Done

Merged PR with validation, rate limiting, standardized ProblemDetails, updated docs, and passing tests.

Estimated Effort

Small-Medium (3-5h).

Depends on: Issue #8 (domain exceptions), Issue #10 (for tracing context beneficial).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions