Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
477 changes: 477 additions & 0 deletions app/dependencies.py

Large diffs are not rendered by default.

1,465 changes: 211 additions & 1,254 deletions app/main.py

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion app/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
"""ReliAPI Routes Package."""
"""ReliAPI Routes Package.

This package contains all route handlers organized by domain:

Core routes:
- health: Health check and monitoring endpoints
- proxy: HTTP and LLM proxy endpoints
- rapidapi: RapidAPI integration endpoints

Business routes:
- paddle: Paddle payment integration
- onboarding: Self-service API key generation
- analytics: Usage analytics tracking
- calculators: ROI/pricing calculators
- dashboard: Admin dashboard
"""
from reliapi.app.routes import health, proxy, rapidapi

__all__ = ["health", "proxy", "rapidapi"]
26 changes: 12 additions & 14 deletions app/routes/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
This module provides analytics endpoints for tracking user behavior,
conversion funnels, and events. All tracking is automated through APIs.
"""

import base64
import json
import logging
import os
from typing import Dict, Any, Optional, List
from datetime import datetime, timedelta
from fastapi import APIRouter, Request, Header, Body
from pydantic import BaseModel, Field
from typing import Any, Dict, Optional

import httpx
from fastapi import APIRouter, Request
from pydantic import BaseModel, Field

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/analytics", tags=["analytics"])

Expand Down Expand Up @@ -174,16 +179,12 @@ async def _track_google_analytics(event_data: Dict[str, Any], ga_id: str) -> Non
timeout=5.0,
)
except Exception as e:
# Log error but don't fail the request
print(f"Google Analytics tracking error: {e}")
logger.warning(f"Google Analytics tracking error: {e}")


async def _track_mixpanel(event_data: Dict[str, Any], token: str) -> None:
"""Track event in Mixpanel."""
try:
import base64
import json

# Mixpanel uses base64 encoded JSON
event_payload = {
"event": event_data["event_name"],
Expand All @@ -203,8 +204,7 @@ async def _track_mixpanel(event_data: Dict[str, Any], token: str) -> None:
timeout=5.0,
)
except Exception as e:
# Log error but don't fail the request
print(f"Mixpanel tracking error: {e}")
logger.warning(f"Mixpanel tracking error: {e}")


async def _track_posthog(event_data: Dict[str, Any], api_key: str, host: str) -> None:
Expand All @@ -222,6 +222,4 @@ async def _track_posthog(event_data: Dict[str, Any], api_key: str, host: str) ->
timeout=5.0,
)
except Exception as e:
# Log error but don't fail the request
print(f"PostHog tracking error: {e}")

logger.warning(f"PostHog tracking error: {e}")
99 changes: 86 additions & 13 deletions app/routes/health.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,104 @@
"""Health check endpoints.
"""Health check and monitoring endpoints.

This module provides health check endpoints for load balancers and monitoring.
The actual health endpoints are defined in reliapi.app.main, this module
is provided for api-template compatibility.
This module provides:
- GET /health - Basic health check
- GET /healthz - Kubernetes-style health check
- GET /readyz - Readiness check
- GET /livez - Liveness check
- GET /metrics - Prometheus metrics
"""
import logging

from fastapi import APIRouter
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import Response
from prometheus_client import CONTENT_TYPE_LATEST, generate_latest
from pydantic import BaseModel

router = APIRouter()
from reliapi.app.dependencies import get_app_state

logger = logging.getLogger(__name__)

router = APIRouter(tags=["Health"])


class HealthResponse(BaseModel):
"""Health check response model."""

status: str
version: str
version: str = "1.0.7"


class StatusResponse(BaseModel):
"""Simple status response model."""

status: str


def _check_health_rate_limit(request: Request, prefix: str) -> None:
"""Check rate limit for health endpoints.

Args:
request: FastAPI request
prefix: Rate limit prefix (e.g., 'healthz', 'metrics')

Raises:
HTTPException: If rate limit exceeded
"""
state = get_app_state()

if not state.rate_limiter:
return

client_ip = request.client.host if request.client else "unknown"
limit = 10 if prefix == "metrics" else 20

allowed, error = state.rate_limiter.check_ip_rate_limit(
client_ip, limit_per_minute=limit, prefix=prefix
)

if not allowed:
if prefix == "metrics":
logger.warning(f"Rate limit exceeded for /metrics endpoint: IP={client_ip}")

raise HTTPException(
status_code=429,
detail={
"type": "rate_limit_error",
"code": error,
"message": f"Rate limit exceeded for {prefix} endpoint.",
},
)


@router.get("/health", response_model=HealthResponse)
async def health_check() -> HealthResponse:
"""Health check endpoint for load balancers and monitoring."""
return HealthResponse(status="ok", version="1.0.7")
"""Basic health check endpoint for load balancers and monitoring."""
return HealthResponse(status="ok")


@router.get("/healthz", response_model=StatusResponse)
async def healthz(request: Request) -> StatusResponse:
"""Kubernetes-style health check endpoint with optional rate limiting."""
_check_health_rate_limit(request, "healthz")
return StatusResponse(status="healthy")


@router.get("/readyz", response_model=StatusResponse)
async def readyz(request: Request) -> StatusResponse:
"""Readiness check endpoint with optional rate limiting."""
_check_health_rate_limit(request, "readyz")
return StatusResponse(status="ready")


@router.get("/livez", response_model=StatusResponse)
async def livez(request: Request) -> StatusResponse:
"""Liveness check endpoint with optional rate limiting."""
_check_health_rate_limit(request, "livez")
return StatusResponse(status="alive")

@router.get("/healthz", response_model=HealthResponse)
async def healthz() -> HealthResponse:
"""Kubernetes-style health check endpoint."""
return HealthResponse(status="ok", version="1.0.7")

@router.get("/metrics")
async def metrics(request: Request) -> Response:
"""Prometheus metrics endpoint with rate limiting."""
_check_health_rate_limit(request, "metrics")
return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST)
Loading
Loading