A FastAPI service that integrates with Google's Gemini API, using Redis and PostgreSQL for response caching to minimize API calls.
- FastAPI: Modern, fast web framework for building APIs
- Gemini API Integration: Calls Google's Gemini AI API with custom prompts
- Two-Tier Caching:
- Redis for fast in-memory caching
- PostgreSQL for persistent storage
- Pydantic Models: Type-safe request/response validation
- RFC 9457 Error Handling: Standardized error responses following Problem Details specification
- Service Error Handling: Gemini API errors return 503 Service Unavailable
- CORS Support: Configurable via environment variables for cross-origin requests
- Swagger Documentation: Auto-generated API documentation at
/docs - Docker Support: Easy deployment with Docker Compose
Calls the Gemini API with a custom prompt. Responses are cached to avoid overcalling the API.
Request Body:
{
"hash": "unique_identifier",
"expected": "expected_value_or_context"
}Response:
{
"badge": "TRUSTED",
"details": "Detailed analysis from Gemini API"
}Response Fields:
badge: Trust classification, one of:TRUSTED: The data is classified as trustedUNTRUSTED: The data is classified as untrustedUNKNOWN: Unable to determine trust level
details: Detailed analysis and reasoning from Gemini API
- Python 3.11+
- Poetry (for dependency management) or pip
- Docker and Docker Compose (for containerized setup)
- Google Gemini API key
# Install Poetry in a virtual environment
make install-poetry
# Install dependencies
make install
# Run development server
make dev
# Run tests
make test- Install Poetry if not already installed:
curl -sSL https://install.python-poetry.org | python3 -
# Or use Makefile: make install-poetry- Install dependencies:
poetry install
# Or use Makefile: make install- Activate the virtual environment:
poetry shell- Create a virtual environment:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate- Install dependencies:
pip install -r requirements.txtThe project includes a Makefile for common tasks:
make help # Show available commands
make install-poetry # Install Poetry in a virtual environment
make install # Install dependencies with Poetry
make dev # Run development server with hot reload
make run # Run production server
make test # Run tests with test databases
make lint # Run linters (ruff, black)
make format # Format code with black and isort
make docker-up # Start Docker services
make docker-down # Stop Docker services
make clean # Clean up generated files
make build # Build project with Poetry- Copy the example environment file:
cp .env.example .env- Edit
.envand configure the application:
# Required: Add your Gemini API key
GEMINI_API_KEY=your_actual_api_key_here
# Database Configuration (if using local PostgreSQL instead of Docker)
# Replace 'postgres' with your PostgreSQL username
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
# Optional: Configure CORS (default allows all origins)
CORS_ENABLED=true
CORS_ORIGINS=*
CORS_CREDENTIALS=true
CORS_METHODS=*
CORS_HEADERS=*
# Optional: Configure Database Connection Pool
DB_POOL_SIZE=5
DB_MAX_OVERFLOW=10
DB_POOL_TIMEOUT=30
DB_POOL_RECYCLE=3600
DB_POOL_PRE_PING=trueNote: If you encounter role "postgres" does not exist error when running make dev, you need to:
- Either use Docker:
make docker-up(recommended) - Or update
POSTGRES_USERin.envto match your local PostgreSQL username (often your system username)
CORS Configuration Options:
CORS_ENABLED: Enable/disable CORS (true/false)CORS_ORIGINS: Allowed origins. Use*for all, or comma-separated list:http://localhost:3000,https://example.comCORS_CREDENTIALS: Allow credentials (true/false)CORS_METHODS: Allowed HTTP methods. Use*for all, or comma-separated list:GET,POST,PUTCORS_HEADERS: Allowed headers. Use*for all, or comma-separated list
Database Pool Configuration Options:
DB_POOL_SIZE: Number of connections to maintain in the pool (default: 5)DB_MAX_OVERFLOW: Maximum number of connections that can be created beyond pool_size (default: 10)DB_POOL_TIMEOUT: Seconds to wait before giving up on getting a connection from the pool (default: 30)DB_POOL_RECYCLE: Seconds after which a connection is automatically recycled (default: 3600)DB_POOL_PRE_PING: Enable connection health checks before using (default: true)
Start all services (API, PostgreSQL, Redis):
docker-compose up -dThe API will be available at http://localhost:8000
View logs:
docker-compose logs -f apiStop services:
docker-compose down- Start PostgreSQL and Redis (using Docker):
docker-compose up postgres redis -d- Run the application:
Using Poetry:
poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# Or use the Poetry script
poetry run devUsing pip/venv:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadOnce the application is running, visit:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
The API follows RFC 9457 (Problem Details for HTTP APIs) for consistent error responses.
All errors return a standardized JSON structure with Content-Type: application/problem+json:
{
"type": "https://datatracker.ietf.org/doc/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"detail": "Specific error description",
"instance": "/api/endpoint"
}- 422 Unprocessable Entity: Validation errors (missing or invalid request fields)
- 404 Not Found: Endpoint not found
- 503 Service Unavailable: Gemini API is unavailable or failed to respond
- 500 Internal Server Error: Unexpected server errors
Validation Error (422):
{
"type": "https://datatracker.ietf.org/doc/html/rfc4918#section-11.2",
"title": "Validation Error",
"status": 422,
"detail": "hash: field required; expected: field required",
"instance": "/gemini"
}Service Unavailable (503):
{
"type": "https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.4",
"title": "Service Unavailable",
"status": 503,
"detail": "Gemini API is currently unavailable",
"instance": "/gemini"
}backend/
├── app/
│ ├── __init__.py # Package marker
│ ├── main.py # FastAPI application setup
│ ├── controllers.py # API endpoint controllers
│ ├── models.py # Pydantic models for request/response
│ ├── config.py # Configuration and settings
│ ├── database.py # PostgreSQL database setup
│ ├── redis_client.py # Redis client wrapper
│ └── gemini_service.py # Gemini API integration
├── tests/ # Test suite
│ ├── conftest.py # Test fixtures
│ ├── test_controllers.py # API endpoint tests
│ ├── test_database.py # Database tests
│ └── test_models.py # Model validation tests
├── docker-compose.yml # Docker services configuration
├── docker-compose-tests.yml # Test databases configuration
├── Dockerfile # Application container definition
├── pyproject.toml # Poetry configuration and dependencies
├── requirements.txt # Python dependencies (pip)
├── pytest.ini # Pytest configuration
├── .env.example # Example environment variables
└── README.md # This file
The Gemini API is configured to perform security analysis and classify data as TRUSTED, UNTRUSTED, or UNKNOWN.
To customize the prompt sent to Gemini API, edit the generate_response method in app/gemini_service.py:
prompt = f"""
Your custom security analysis prompt here...
Hash: {hash_value}
Expected: {expected_value}
Format your response as:
CLASSIFICATION: [TRUSTED/UNTRUSTED/UNKNOWN]
DETAILS: [Your detailed analysis]
"""- First Request: Calls Gemini API, stores badge and details in both Redis and PostgreSQL
- Subsequent Requests:
- Checks Redis first (fast, in-memory)
- Falls back to PostgreSQL if not in Redis
- Only calls Gemini API if not found in either cache
- Cached responses return the same badge and details as the original API call
Using curl:
curl -X POST http://localhost:8000/gemini \
-H "Content-Type: application/json" \
-d '{"hash": "test123", "expected": "test value"}'Using Python:
import requests
response = requests.post(
"http://localhost:8000/gemini",
json={"hash": "test123", "expected": "test value"}
)
print(response.json())The project includes comprehensive tests with mocked Gemini API responses and real test databases.
Install test dependencies:
Using Poetry:
poetry install --with devUsing pip:
pip install -r requirements.txtUse the provided script that manages test databases:
./run_tests.shOr manually:
- Start test databases:
docker compose -f docker-compose-tests.yml up -d- Run tests:
Using Poetry:
poetry run pytest -vUsing pip/venv:
pytest -v- Stop test databases:
docker compose -f docker-compose-tests.yml downtests/
├── conftest.py # Test fixtures and configuration
├── test_controllers.py # API endpoint tests with mocked Gemini
├── test_database.py # Database operations tests
└── test_models.py # Pydantic model validation tests
Key Features:
- Mocked Gemini API: Tests don't call the real Gemini API
- Real Databases: Uses PostgreSQL and Redis test instances via Docker
- Isolated Tests: Each test gets a fresh database session
- Comprehensive Coverage: Tests for all endpoints, models, and database operations
The test suite uses separate database instances:
- PostgreSQL: Port 5433 (vs 5432 for dev)
- Redis: Port 6380 (vs 6379 for dev)
Configuration is in docker-compose-tests.yml.
See LICENSE file for details.