Alberto Moretti f367692287
All checks were successful
Rust / test (push) Successful in 1m2s
Rust / check (push) Successful in 1m23s
Docker / build (push) Successful in 2m4s
ci: avoid qemu on local runners
2026-06-16 13:59:34 +02:00
2026-06-15 12:35:58 +02:00
2026-06-15 12:26:26 +02:00
2026-06-15 12:26:26 +02:00
2026-06-13 06:05:45 +02:00
2026-06-13 06:05:45 +02:00
2026-06-13 06:12:51 +02:00
2026-06-15 12:26:26 +02:00
2026-06-15 12:35:58 +02:00
2026-06-15 12:26:26 +02:00
2026-06-16 13:53:39 +02:00

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.

File challenge

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:

make docker-build
make docker-run

Option B: local Rust

Install Rust with rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustup default stable

Then run the service:

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:

make cli-health
make cli-pokemon
make cli-translated
make cli-pokemon POKEMON=pikachu BASE_URL=http://localhost:5000

Endpoints

make health
make pokemon
make translated
make metrics

Example response:

{
  "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

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

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:

make contract-test

Docker multi-arch build

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.

Description
Truelayer interview
Readme 258 KiB
Languages
Rust 92.7%
Dockerfile 4.7%
Makefile 2.6%