# Pokedex API REST API for the TrueLayer Software Engineering Challenge. It returns basic Pokémon information from PokéAPI and, on request, a fun translated description from FunTranslations. ## Requirements You can run it either with Docker or with a local Rust toolchain. Common commands are available through `make`; run `make help` for the full list. ### Option A: Docker Install Docker Desktop or an equivalent Docker runtime, then run: ```bash make docker-build make docker-run ``` ### Option B: local Rust Install Rust with rustup: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source "$HOME/.cargo/env" rustup default stable ``` Then run the service: ```bash make run ``` The API listens on `0.0.0.0:5000` by default. ## CLI helper With the API running in another terminal, call it through the small helper binary: ```bash make cli-health make cli-pokemon make cli-translated make cli-pokemon POKEMON=pikachu BASE_URL=http://localhost:5000 ``` ## Endpoints ```bash make health make pokemon make translated make metrics ``` Example response: ```json { "name": "mewtwo", "description": "It was created by a scientist after years of horrific gene splicing and DNA engineering experiments.", "habitat": "rare", "isLegendary": true } ``` ## Translation rules `/pokemon/translated/{name}` applies Yoda when the Pokémon is legendary or its habitat is `cave`; otherwise it applies Shakespeare. If translation fails or returns an empty result, the API falls back to the standard PokéAPI description. ## Architecture ```mermaid flowchart LR CLI[CLI helper] --> HTTP[HTTP layer] HTTP --> APP[Application service] APP --> DOMAIN[Domain] APP --> CLIENTS[External clients] HTTP --> OTEL[Telemetry] APP --> OTEL ``` See `docs/architecture.md` for the design notes. ## Configuration | Variable | Default | Description | | --- | --- | --- | | `BIND_ADDR` | `0.0.0.0:5000` | HTTP bind address | | `POKEAPI_BASE_URL` | `https://pokeapi.co/api/v2` | PokéAPI base URL | | `FUN_TRANSLATIONS_BASE_URL` | `https://api.funtranslations.mercxry.me/v1` | FunTranslations base URL | | `REQUEST_TIMEOUT_SECONDS` | `5` | Upstream HTTP timeout | | `RATE_LIMIT_PER_SECOND` | `20` | Global token refill rate | | `RATE_LIMIT_BURST` | `40` | Global burst capacity | | `OTEL_SERVICE_NAME` | `pokedex-api` | OpenTelemetry service name | | `RUST_LOG` | `pokedex_api=info,tower_http=info` | JSON tracing log filter | ## Instrumentation The service includes: - structured JSON logging via `tracing` - request spans via `tower-http` - `x-request-id` generation and propagation - OpenTelemetry metrics for HTTP requests, HTTP errors, upstream calls, upstream errors and latency histograms - `/metrics` in Prometheus text format backed by OpenTelemetry instruments - simple global token-bucket rate limiting returning `429` ## Development checks ```bash make check ``` The crate denies unsafe code and enables strict Clippy groups: `all`, `pedantic`, `nursery` and `cargo`, with only dependency-version noise allowed. ## External contract checks Normal tests mock third-party APIs. A scheduled GitHub Actions workflow runs ignored contract tests nightly against the real PokéAPI and FunTranslations APIs to catch provider contract drift early: ```bash make contract-test ``` ## Docker multi-arch build ```bash make docker-buildx ``` The Dockerfile uses `cargo-chef` and BuildKit cache mounts for dependency and target directory caching. ## Production notes For a production API I would add per-client or per-token rate limiting instead of one global bucket, retries with bounded exponential backoff, circuit breakers for upstream failures, and a bounded LRU/TTL cache for PokéAPI data. Species content changes rarely, so caching successful responses would avoid unnecessary random upstream hits, reduce latency, and make transient provider failures less visible to users. I would also add stronger health checks that distinguish readiness from liveness, dashboards and alerts from the OTEL metrics, and a dedicated OTEL collector pipeline. I would keep `/metrics` private, add dependency/container scanning, define SLOs, and add contract tests against recorded upstream fixtures.