95ulisse / truelayer-pokemon-challenge

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TrueLayer Pokemon Challenge

The challenge has been solved using Rust and tested with stable Rust 1.52.

Building and running

The application can be easily run using the provided Dockerfile.

Install Docker as described here, and then run from the root of the project:

docker build -t truelayer-pokemon-challenge .
docker run --rm -ti -p 8080:8080 truelayer-pokemon-challenge

The server will be available at http://localhost:8080.

$ curl http://localhost:8080/pokemon/pikachu
{"name":"pikachu","description":"At which hour several of these pokémon gather, [...]"}

Running the tests

Tests can also be run using the provided Dockerfile.

docker build -t truelayer-pokemon-challenge-test -f Dockerfile.test .
docker run --rm -ti truelayer-pokemon-challenge-test

General description

The API is implemented with Rust using warp.

When a request for a new Pokemon description comes in, the following happens:

  1. The Pokemon name is validated using the PokeAPI and its description retrieved.
  2. The PokeAPI returns more than one description, so we select the first one available in the English language.
  3. We send a request to the Shakespeare Translator to translate the description into Shakespearean language.
  4. The result is cached for further requests in an in-memory LRU cache.

Exposed routes

  • GET /pokemon/{string}: Returns the translated description of the Pokemon with the given name.

  • GET /health: Healthcheck endpoint used to check whether the application is alive or not.

  • GET /metrics: Endpoint to scrape Prometheus metrics generated by the application.

Configuration

The configuration of the application can be tweaked using the following environment variables

  • PORT: Port to bind the server to.
  • RUST_LOG: Logging configuration. Look here for documentation on the format.
  • SHAKESPEARE_TRANSLATOR_ENDPOINT: Base url of the Shakespeare Translator API.
  • POKEAPI_ENDPOINT: Base url of the Pokemon API.
  • POKEAPI_CACHE_SIZE: Number of Pokemons to keep in the LRU cache.

Areas of improvement

Due to the short time of the challenge, a few important aspects have been glossed over.

Here are some possible areas of improvement:

  • Better error handling

    • The errors have been handled using anyhow, while a proper application should define its internal Error types for proper pattern matching and error handling.
    • Better handling of rate limit errors for Shakespeare API, which has a hard limit of 5 calls/hour. When a rate limit error is encountered, it is just logs the error and returns an HTTP 500 to the client. It would be better to properly handle the situation and return an HTTP 429.
  • Reliability of the calls to external services

    • Temporary errors could be retried.
    • Limit the maximum number of concurrently in-flight requests to external services. Right now, if two requests for the same uncached Pokemon arrive at the same time, two duplicate requests are sent to the external APIs. Those requests could be deduped in order to improve performance.
  • Caching

    • In this scenario is very important to cache the translated descriptions in order to reduce the number of calls to external services and improve performance. The data handled by this application is static and readonly, which means that it is very cache-friendly. Right now, a very simple in-memory LRU cache implements a memory-bounded cache which could be swapped for a more proper solution like Redis.
  • HTTP metrics

    • Observability is paramount in a complex distributed system. The application exposes metrics about the number of requests made to the external APIs and the number of cache hits. A true production-ready application would also expose metrics about the timings of the response and other statistics about the process.

About


Languages

Language:Rust 96.3%Language:Dockerfile 3.7%