Test

Python 3.10.6

!LET'S MAKE SOME MONEY LAD/LASS!(read with scottish accent)

πŸ¦† πŸ’²SCROOGE MCDUCK CURRENCY FLASK API- CURRENCY CHALLENGE BRAVOπŸ’² πŸ¦†


ScroogeMcDuckCurrencyApi is a multi currency support application, that allows the user to:

  • Convert amounts from a currencie to anothers
  • Creates it's own currency based on dollar exchange rate
  • Execute basic RestFull methods, such as: Find, update, and delete.

This API was built with Flask APP and Flask-restx, therefore it can be used integrated with Swagger.ui interface.

πŸ“–Docs Available Languages:

πŸ‘·Third-Party Service - OpenExchangeAPI


Since Currency ratios are constantly getting updated, it is not possible for a humanbeeing to keep updating all currencies data, in order to convert amounts dynamically. For that reason, ScroogeMcDuckCurrencyApi is integrated with OpenExchangeAPI free Api currency service.
Howerver, once the user checks for a currency or whatever methods, ScroogeMcDuckCurrencyApi will not directly consult OpenExchange, but it's own database. Data that comes from OpenExchange is dynamically updated according to system scheduling configuration, to be explained in configuration section.

πŸ’΅ Dollar conversion rate

ScroogeMcDuckCurrencyApi works based on dollar conversion rate, thus every currency must be converted from its value to dollar, before getting converted into another currency.

Let's make an example:

If you want to convert Scrooge McDuck's own currency into BRL (Brazilian's currency), you must have McDuck's currency dollar conversion rate, or how many McDuck's coins you need to make it into a doller.

Let's say McDuck's dollar conversion rate is 2 (which is not possible since he is way too much rich), then you need 2 McDuck's coins to make a dollar. Nowadays (and this is impressively scary), the dollar conversion rate from BRL to USD(Dollar universal identifier) is 5.22. To convert 5 McDuck's into Reais, we do:

(5/2)*5.22 = 13.05 Reais

Math is fantastic!

πŸ’‰Dependency Injection

In order to use dependency injection concepts and tools, this API uses python Injector. I had to come around with some logics to make it work fine wich performed, IMHO, just fine and looks pretty well.

⌚Scheduler

ScroogeMcDuckCurrencyApi perform cronologic operations to update the database with OpenExchange api.
Dispite the fact that python has planty of libraries for scheduling and queueing, such as: schedule,Croniter or flask-cronjob , this service does not use such tools, intenting to look for a leanest approach.

πŸ“”Data storage


ScroogeMcDuckCurrencyApi has a mongoDb database to store data from OpenExchange and inputed by users.
Using mongo makes easy to use the fantastic mongoengine python ORM package, since it provides a much better view of the code with object models.

❗❗ Disclaimer


ScroogeMcDuckCurrencyApi has a pretty nice interface and performs just fine given it's objective, however it does not perform automatic updates for currencies that are not provided by OpenExchange API, in that way, in order to update custom currencies, the user must keep it up to date manually or create a provider to perform updates on the API from its source.

ScroogeMcDuckCurrencyApi source code has some worth looking comments that you can check, by looking for NOTES:

βš™οΈ Api Configuration


Despite the fact that this application only uses free resources, life is not always a bed of roses, we have some secrets to hide πŸ•΅οΈ and some config to do. In fact, we only have one secret, to be explained as it follows.

OpenExchange APP ID


OpenExchange provides a Free to use API, but, in order to use this API, you must have an account at open exchange. For that:

Obs: If you intent to run this application using a IDE, just save your Open Exchange app id as an environment variable with name OPENEXCHANGE_APP_ID.

Database Update Scheduler


By default, the API updates the database with openExchange api every 10 minutes, but if you want to increase or decrease (who knows?) this delay, just replace the value of UPDATE_CURRENCIES_MINUTES_SCHEDULE at docker-compose file

Obs: Just like the previous section, if you are running the api locally in your IDE, update the environment variable UPDATE_CURRENCIES_MINUTES_SCHEDULE.

πŸƒRunning the application

First of all, clone the repository:

git clone git@github.com:raul-macedo-freire/currency-challenge-bravo-api.git

In order to run the api, you have two options:

  • Run with docker-compose
  • Run with an IDE

Run with docker-compose

If you are not used to work with docker, take a look at the docs and install docker-compose.

After getting used to docker, configure the docker-compose file, according to the Api Configuration Section

In the project Folder, run:

docker compose up

Check the application interface at : https://localhost:5000/swagger

Run with an IDE

Save the environment variables according to the Api Configuration Observations.

If you are not using a dependency manager, I strongly recommend using something like pytest.

If you don't want to use pyenv and go for it installing dependencies into global python environment(who knows?), skip to Installing Dependencies section.

Setup Python Environmnet:

This project uses python 3.10.6, I'll consider that you're using pyenv for python version management, if you're not, check for you dependencies manager configuration and follow the steps below in a equivalent way.

Check the python version:

python --version

If you're not using version 3.10.6, check if you have it installed, with:

pyenv versions

If you don't, install the version with:

pyenv install -v 3.10.6

Then set the version locally:

pyenv local 3.10.6

In the API root directory, create a new python environment:

python -m venv <virtual-env-name>

Activate the virtual environment

source <virtual-env-name>/bin/activate

if you're using windows access the virtual environment with:

 .\venv\Scripts\activate

Installing Dependencies:

pip install -r requirements.txt

Running the app:

If you're using VSCODE, I have already provided a Run script with a launch file, so if it's the case:

  • Save the environment variables in a .env file
  • Run the run application script with F5 shortcut.

If you're not using VSCODE, start using it, take a look at your IDE configuration and run the app from the run.py root file and don't forget to save the environment variables in configuration.

Check the application interface at : https://localhost:5000/swagger

!!!NOTE!!!: If you run the app like this, you won't be able to run api requests, since the database won't be running.

πŸ§ͺ Running Tests

Unit tests

To run all unit tests, use:

python -m pytest

Stress tests

This application uses k6.io tool to perform stress tests. Check the k6 documentation to install the tool.

To run the test, from the application root, enter the tests folder:

cd ./tests

And run the test:

k6 run sovietic_attack.js 

Obs1: Don't forget to have the application up and running before running the test

Obs2: In order to performe more accurate the tests for the API, each endpoint must be tested individually, following the considerations, if you want to test each endpoint, uncomment the endpoint and comment the rest (or not, nobody rules you Β―\_(ツ)_/Β― ).


😎 Final Considerations

If you are really bad with examples and don't know how to start trying the API, take a look at postman_examples. If you don't know postman, I strongly advise you to give it a try :D

Summarized documentation:

Project Structure

currency-challenge-bravo-api
β”œβ”€ .github
β”‚  └─ workflows
β”‚     β”œβ”€ readme.yml
β”‚     └─ Tests.yml
β”œβ”€ .gitignore
β”œβ”€ .vscode
β”‚  β”œβ”€ launch.json
β”‚  └─ settings.json
β”œβ”€ app
β”‚  β”œβ”€ api.py
β”‚  β”œβ”€ config
β”‚  β”‚  β”œβ”€ config.ini
β”‚  β”‚  └─ config_helper.py
β”‚  β”œβ”€ controllers
β”‚  β”‚  β”œβ”€ base_controller.py
β”‚  β”‚  β”œβ”€ currencies_controller.py
β”‚  β”‚  β”œβ”€ currency_controller.py
β”‚  β”‚  β”œβ”€ currency_converter_controller.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ core
β”‚  β”‚  β”œβ”€ entities
β”‚  β”‚  β”‚  β”œβ”€ currency.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”œβ”€ exceptions
β”‚  β”‚  β”‚  β”œβ”€ base_exceptions.py
β”‚  β”‚  β”‚  β”œβ”€ client_errors
β”‚  β”‚  β”‚  β”‚  β”œβ”€ currency_not_found.py
β”‚  β”‚  β”‚  β”‚  β”œβ”€ parameters_missing_error.py
β”‚  β”‚  β”‚  β”‚  β”œβ”€ validation_error.py
β”‚  β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”‚  β”œβ”€ server_errors
β”‚  β”‚  β”‚  β”‚  β”œβ”€ configuration_error.py
β”‚  β”‚  β”‚  β”‚  β”œβ”€ external_service_error.py
β”‚  β”‚  β”‚  β”‚  β”œβ”€ infra_service_unauthorized.py
β”‚  β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ infra
β”‚  β”‚  β”œβ”€ models
β”‚  β”‚  β”‚  β”œβ”€ currency_model.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”œβ”€ repositories
β”‚  β”‚  β”‚  β”œβ”€ currency_repository.py
β”‚  β”‚  β”‚  β”œβ”€ interfaces
β”‚  β”‚  β”‚  β”‚  β”œβ”€ abstract_currency_repository.py
β”‚  β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”œβ”€ services
β”‚  β”‚  β”‚  β”œβ”€ interfaces
β”‚  β”‚  β”‚  β”‚  β”œβ”€ abstract_external_currency_service.py
β”‚  β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”‚  β”œβ”€ open_exchanges_api_service.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ ioc.py
β”‚  β”œβ”€ middleware
β”‚  β”‚  β”œβ”€ exception_middleware.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ models
β”‚  β”‚  β”œβ”€ input_model
β”‚  β”‚  β”‚  β”œβ”€ base_input_model.py
β”‚  β”‚  β”‚  β”œβ”€ currency_converter_query_parameters_input_model.py
β”‚  β”‚  β”‚  β”œβ”€ currency_input_model.py
β”‚  β”‚  β”‚  β”œβ”€ update_currency_input_model.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  β”œβ”€ view_model
β”‚  β”‚  β”‚  β”œβ”€ base_view_model.py
β”‚  β”‚  β”‚  β”œβ”€ get_currencies_view_model.py
β”‚  β”‚  β”‚  β”œβ”€ get_currency_view_model.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ scheduler.py
β”‚  β”œβ”€ services
β”‚  β”‚  β”œβ”€ converter_service.py
β”‚  β”‚  β”œβ”€ currency_service.py
β”‚  β”‚  β”œβ”€ interfaces
β”‚  β”‚  β”‚  β”œβ”€ abstract_converter_service.py
β”‚  β”‚  β”‚  β”œβ”€ abstract_currency_service.py
β”‚  β”‚  β”‚  └─ __init__.py
β”‚  β”‚  └─ __init__.py
β”‚  β”œβ”€ update_db_worker.py
β”‚  └─ __init__.py
β”œβ”€ docker-compose.yml
β”œβ”€ Dockerfile
β”œβ”€ LICENSE
β”œβ”€ mongo-init.js
β”œβ”€ README.es.md
β”œβ”€ README.md
β”œβ”€ README.pt.md
β”œβ”€ requirements.txt
β”œβ”€ run.py
└─ tests
   β”œβ”€ app
   β”‚  β”œβ”€ core
   β”‚  β”‚  β”œβ”€ entities
   β”‚  β”‚  β”‚  β”œβ”€ test_currency.py
   β”‚  β”‚  β”‚  └─ __init__.py
   β”‚  β”‚  └─ __init__.py
   β”‚  β”œβ”€ infra
   β”‚  β”‚  β”œβ”€ repositories
   β”‚  β”‚  β”‚  β”œβ”€ test_currency_repository.py
   β”‚  β”‚  β”‚  └─ __init__.py
   β”‚  β”‚  β”œβ”€ services
   β”‚  β”‚  β”‚  β”œβ”€ test_open_exchanges_api_service.py
   β”‚  β”‚  β”‚  └─ __init__.py
   β”‚  β”‚  └─ __init__.py
   β”‚  β”œβ”€ services
   β”‚  β”‚  β”œβ”€ test_converter_service.py
   β”‚  β”‚  β”œβ”€ test_currency_service.py
   β”‚  β”‚  └─ __ini__.py
   β”‚  └─ __init__.py
   β”œβ”€ sovietic_attack.js
   β”œβ”€ tests_helper
   β”‚  β”œβ”€ factory
   β”‚  β”‚  β”œβ”€ factory.py
   β”‚  β”‚  └─ __init__.py
   β”‚  β”œβ”€ requests_mock.py
   β”‚  └─ __init__.py
   └─ __init__.py