Welcome to the MB project which is a sample project written in Python with FastAPI!
This project was created to demonstrate my knowledge of Python, FastAPI, and Clean Architecture.
This document will help you understand the project structure and get started quickly.
# First time setup
make setup
# Copy .env.example to .env and edit it with your configuration
cp .env.example .env
# Start the application environment with Docker Compose
make up/build
Open a new browser tab and navigate to http://localhost:8000/docs or http://localhost:8000/redoc to see the API documentation.
.
├── app/ # Source code directory
│ ├── data/ # Data layer
│ ├── domain/ # Domain layer
│ ├── presentation/ # Presentation layer
│ ├── utils/ # Utility functions
│ └── main.py # Application entry point
├── test/ # Test files
│ ├── integration/ # Integration tests
│ ├── unit/ # Unit tests
│ └── conftest.py # Test configuration file
├── .dockerignore # Docker ignore file
├── .env.example # Environment variables example to be copied as .env locally
├── Dockerfile # Dockerfile for building the Docker image
├── main.py # Application entry point
├── Makefile # Makefile with multiple useful commands
├── README.md # This file
├── requirements-dev.in # Development dependencies input file for pip-tools
├── requirements-dev.txt # Development dependencies output file for pip-tools
├── requirements.in # Production dependencies input file for pip-tools
└── requirements.txt # Production dependencies output file for pip-tools
- Python 3.8 or later
- pip3 (Python package installer)
- Docker and Docker Compose
- Make (for using Makefile commands)
- Clone the repository:
git clone git@github.com:0xfbravo/mb.git
cd mb
- Set up the development environment:
make setup
- Set up environment variables:
cp .env.example .env
# Edit .env with your configuration
- Install the package in development mode:
make install
- Run the development server:
make run
This application is configured to work with any EVM compatible blockchain.
By default, the application is configured to work with the TEST
network.
So if you want to use, for example, the ETHEREUM_SEPOLIA
network, you need to change the selected
network in the config.yaml
file to ETHEREUM_SEPOLIA
.
Also you can configure the assets and networks in the config.yaml
file, you just need to add the asset and network you want to use.
assets:
USDT:
native: false
ETHEREUM: "0xdac17f958d2ee523a2206206994597c13d831ec7"
ARBITRUM: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"
BASE: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2" # Bridged USDT
# ETHEREUM_SEPOLIA: "0x0000000000000000000000000000000000000000" # Unable to find official contract address
# ARBITRUM_SEPOLIA: "0x0000000000000000000000000000000000000000" # Unable to find official contract address
# BASE_SEPOLIA: "0x0000000000000000000000000000000000000000" # Unable to find official contract address
The project follows Clean Architecture principles with clear separation of concerns:
-
Presentation (
app/presentation
)- Implements REST API endpoints (e.g.
app/presentation/api/
) - Handles request/response transformation
- Calls domain layers to perform business logic
- Can interact with user's input and output in multiple ways (e.g. CLI, HTTP, etc.)
- Implements REST API endpoints (e.g.
-
Data (
app/data/
)- Handles external dependencies like database, cache, and external service integrations (e.g.
app/data/evm/
) - Implements data access interfaces
- Handles external dependencies like database, cache, and external service integrations (e.g.
-
Domain (
app/domain/
)- Defines data models and entities split into sub-folders (e.g.
app/domain/wallet/
) - Contains domain-specific logic
- Independent of infrastructure concerns, exclusively responsible for business logic
- Defines data models and entities split into sub-folders (e.g.
The application uses PostgreSQL with Tortoise ORM for database operations and connection pooling.
The database connection pool is managed by Tortoise ORM and can be configured using environment variables:
# Database connection settings
POSTGRES_DB=your_database_name
POSTGRES_USER=your_username
POSTGRES_PASSWORD=your_password
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
# Connection pool settings (optional)
DB_POOL_MIN_SIZE=1 # Minimum number of connections in the pool
DB_POOL_MAX_SIZE=10 # Maximum number of connections in the pool
DB_POOL_MAX_IDLE=300 # Maximum time (seconds) a connection can be idle
DB_POOL_TIMEOUT=30 # Timeout (seconds) for getting a connection from the pool
Run all tests:
make test
Run unit tests only:
make test/unit
Run integration tests:
make test/integration
Run tests with coverage:
make test/all
Generate coverage report:
make coverage
-
Creating a New Feature
- Create a new branch from
main
- Follow the domain-driven structure
- Add tests for new functionality
- Submit a pull request
- Create a new branch from
-
Code Style
- Follow PEP 8 guidelines
- Use
black
andisort
for code formatting - Use
flake8
andmypy
for code quality
-
Documentation
- Document all public APIs
- Update README when adding new features
- Add docstrings for functions and classes
make setup # Setup development environment (venv, tools, dependencies)
make build # Build the Python package
make install # Install the package in development mode
make clean # Clean build artifacts and cache files
make test # Run all tests (unit and integration)
make test/unit # Run unit tests only
make test/integration # Run integration tests
make test/all # Run all tests with coverage
make coverage # Generate test coverage report
make lint # Run linter (flake8 and mypy)
make fmt # Format code with black and isort
make deps # Install dependencies
make deps/update # Update dependencies
make deps/compile # Compile requirements files
make security # Run security checks
make run # Run the application
make run/dev # Run with auto-reload
make mocks # Mock generation info
Add production dependencies to requirements.txt
:
pip3 install package_name
pip3 freeze > requirements.txt
Add development dependencies to requirements-dev.txt
:
pip3 install package_name
pip3 freeze > requirements-dev.txt
For better dependency management, use pip-tools
:
make deps/compile
Each service follows this pattern:
class ServiceImpl:
def __init__(self, repository: Repository, logger: Logger):
self.repository = repository
self.logger = logger
def execute(self, request: Request) -> Response:
# Business logic here
pass
- Use custom exception classes
- Handle errors at appropriate layers
- Return meaningful error messages
- Use structured logging
- Include relevant context in logs
- Log at appropriate levels
- Test individual functions and methods
- Mock external dependencies
- Focus on business logic
- Test component interactions
- Use test databases
- Test API endpoints
- Aim for >80% coverage
- Focus on critical business logic
- Use
pytest-cov
for coverage reporting
Run security checks:
make security
This will:
- Check for known vulnerabilities in dependencies
- Scan for security issues in your code
- Provide recommendations for fixes
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Set up the development environment (
make setup
) - Make your changes
- Run tests (
make test
) - Format your code (
make fmt
) - Run linting (
make lint
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Create a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For support, please:
- Check the documentation
- Search existing issues
- Create a new issue if needed
The project uses GitHub Actions for:
- Running tests
- Linting and formatting checks
- Security scanning
- Building Docker images
- Deploying to environments
-
Code Organization
- Keep files focused and small
- Use meaningful names
- Follow Python idioms and PEP 8
-
Testing
- Write unit tests for business logic
- Include integration tests
- Maintain good test coverage
-
Documentation
- Keep documentation up to date
- Document complex algorithms
- Include examples in docstrings
-
Dependencies
- Pin dependency versions
- Use virtual environments
- Regularly update dependencies
-
Code Quality
- Use type hints
- Follow linting rules
- Format code consistently