latest version of apis event and cahce ablitites added
This commit is contained in:
40
DockerApiServices/AuthServiceApi/Dockerfile
Normal file
40
DockerApiServices/AuthServiceApi/Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies and Poetry
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir poetry
|
||||
|
||||
# Copy Poetry configuration
|
||||
COPY DockerApiServices/pyproject.toml ./pyproject.toml
|
||||
|
||||
# Configure Poetry and install dependencies with optimizations
|
||||
RUN poetry config virtualenvs.create false \
|
||||
&& poetry install --no-interaction --no-ansi --no-root --only main \
|
||||
&& pip cache purge \
|
||||
&& rm -rf ~/.cache/pypoetry
|
||||
|
||||
# Copy application code
|
||||
COPY DockerApiServices/AuthServiceApi /app
|
||||
|
||||
# Copy application code
|
||||
COPY ApiLayers /app/ApiLayers
|
||||
COPY Services /app/Services
|
||||
|
||||
# Events
|
||||
COPY Events/Engine /app/Events/Engine
|
||||
COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
COPY Events/AllEvents/authentication /app/Events/AllEvents/authentication
|
||||
COPY DockerApiServices/AuthServiceApi/events_file.py /app/Events/AllEvents/events_file.py
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/app \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Run the application using the configured uvicorn server
|
||||
CMD ["poetry", "run", "python", "app.py"]
|
||||
27
DockerApiServices/AuthServiceApi/app.py
Normal file
27
DockerApiServices/AuthServiceApi/app.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
FastAPI Application Entry Point
|
||||
|
||||
This module initializes and configures the FastAPI application with:
|
||||
- CORS middleware for cross-origin requests
|
||||
- Request timing middleware for performance monitoring
|
||||
- Custom exception handlers for consistent error responses
|
||||
- Prometheus instrumentation for metrics
|
||||
- API routers for endpoint organization
|
||||
"""
|
||||
|
||||
import uvicorn
|
||||
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
from app_handler import setup_middleware
|
||||
from create_file import create_app
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
app = create_app() # Initialize FastAPI application
|
||||
Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics
|
||||
setup_middleware(app) # Configure middleware and exception handlers
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the application with Uvicorn
|
||||
uvicorn.Server(uvicorn.Config(**ApiConfig.as_dict())).run()
|
||||
84
DockerApiServices/AuthServiceApi/app_handler.py
Normal file
84
DockerApiServices/AuthServiceApi/app_handler.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
FastAPI Application Handler Module
|
||||
|
||||
This module contains all the handler functions for configuring and setting up the FastAPI application:
|
||||
- CORS middleware configuration
|
||||
- Exception handlers setup
|
||||
- Uvicorn server configuration
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI, Request, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import ValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
|
||||
HTTPExceptionApiHandler,
|
||||
validation_exception_handler,
|
||||
)
|
||||
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
|
||||
from ApiLayers.Middleware.auth_middleware import (
|
||||
RequestTimingMiddleware,
|
||||
LoggerTimingMiddleware,
|
||||
)
|
||||
|
||||
|
||||
def setup_cors_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure CORS middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
||||
"""
|
||||
Handle generic exceptions and return formatted error responses.
|
||||
|
||||
Args:
|
||||
request: FastAPI request object
|
||||
exc: Exception instance
|
||||
|
||||
Returns:
|
||||
JSONResponse: Formatted error response
|
||||
"""
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content={"detail": "Internal server error", "error_code": "INTERNAL_ERROR"},
|
||||
)
|
||||
|
||||
|
||||
def setup_exception_handlers(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure custom exception handlers for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
|
||||
app.add_exception_handler(ValidationError, validation_exception_handler)
|
||||
app.add_exception_handler(
|
||||
HTTPExceptionApi, custom_exception_handler.handle_exception
|
||||
)
|
||||
app.add_exception_handler(Exception, generic_exception_handler)
|
||||
|
||||
|
||||
def setup_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure all middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
setup_cors_middleware(app)
|
||||
app.add_middleware(RequestTimingMiddleware)
|
||||
app.add_middleware(LoggerTimingMiddleware)
|
||||
setup_exception_handlers(app)
|
||||
71
DockerApiServices/AuthServiceApi/config.py
Normal file
71
DockerApiServices/AuthServiceApi/config.py
Normal file
@@ -0,0 +1,71 @@
|
||||
class DefaultApiConfig:
|
||||
app: str
|
||||
host: str
|
||||
port: int
|
||||
log_level: str
|
||||
reload: bool
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return {
|
||||
"app": cls.app,
|
||||
"host": cls.host,
|
||||
"port": int(cls.port),
|
||||
"log_level": cls.log_level,
|
||||
"reload": bool(cls.reload),
|
||||
}
|
||||
|
||||
|
||||
class ApiStatic:
|
||||
PLACEHOLDER = "https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg"
|
||||
FORGOT_LINK = "https://www.evyos.com.tr/password/create?tokenUrl="
|
||||
BLACKLIST_LINK = "https://www.evyos.com.tr/support/unknown-login-notice/"
|
||||
APP_DIR = "/home/berkay/git-evyos/api-managment-backend/"
|
||||
|
||||
@classmethod
|
||||
def forgot_link(cls, forgot_key):
|
||||
return cls.FORGOT_LINK + forgot_key
|
||||
|
||||
@classmethod
|
||||
def blacklist_login(cls, record_id):
|
||||
return cls.BLACKLIST_LINK + record_id
|
||||
|
||||
|
||||
class HostConfig:
|
||||
MAIN_HOST = "10.10.2.36" # http://10.10.2.36
|
||||
EMAIL_HOST = "10.10.2.34" # http://10.10.2.34
|
||||
|
||||
|
||||
class ApiConfig(DefaultApiConfig):
|
||||
# Application Information
|
||||
APP_NAME = "evyos-auth-api-gateway"
|
||||
TITLE = "WAG API Auth Api Gateway"
|
||||
DESCRIPTION = (
|
||||
"This api is serves as web auth api gateway only to evyos web services."
|
||||
)
|
||||
APP_URL = "https://www.auth.eys.gen.tr"
|
||||
|
||||
# Server Configuration
|
||||
app = "app:app"
|
||||
host = "0.0.0.0"
|
||||
port = 41575
|
||||
log_level = "info"
|
||||
reload = True
|
||||
|
||||
|
||||
class MainConfig:
|
||||
|
||||
# Date and Time Configuration
|
||||
DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss Z"
|
||||
DATETIME_FORMAT_JS = "YYYY-MM-DD HH:mm:ss +0"
|
||||
|
||||
# Timezone Configuration
|
||||
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
|
||||
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
|
||||
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones
|
||||
|
||||
|
||||
class LanguageConfig:
|
||||
|
||||
SUPPORTED_LANGUAGES = ["en", "tr"]
|
||||
DEFAULT_LANGUAGE = "tr"
|
||||
48
DockerApiServices/AuthServiceApi/create_file.py
Normal file
48
DockerApiServices/AuthServiceApi/create_file.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
FastAPI Application Factory Module
|
||||
|
||||
This module provides functionality to create and configure a FastAPI application with:
|
||||
- Custom OpenAPI schema configuration
|
||||
- Security scheme configuration for Bearer authentication
|
||||
- Automatic router registration
|
||||
- Response class configuration
|
||||
- Security requirements for protected endpoints
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from config import ApiConfig
|
||||
from create_routes import get_all_routers
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
Create and configure a FastAPI application with dynamic route creation.
|
||||
|
||||
Returns:
|
||||
FastAPI: Configured FastAPI application instance
|
||||
"""
|
||||
|
||||
from open_api_creator import create_openapi_schema
|
||||
|
||||
app = FastAPI(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
default_response_class=JSONResponse,
|
||||
) # Initialize FastAPI app
|
||||
|
||||
@app.get("/", include_in_schema=False, summary=str(ApiConfig.DESCRIPTION))
|
||||
def home() -> RedirectResponse:
|
||||
"""Redirect root path to API documentation."""
|
||||
return RedirectResponse(url="/docs")
|
||||
|
||||
# Get all routers and protected routes using the dynamic route creation
|
||||
prepare_routing = get_all_routers()
|
||||
|
||||
# Include all routers
|
||||
for router in prepare_routing.routers:
|
||||
app.include_router(router)
|
||||
|
||||
app.openapi = lambda app=app: create_openapi_schema(app)
|
||||
return app
|
||||
42
DockerApiServices/AuthServiceApi/create_routes.py
Normal file
42
DockerApiServices/AuthServiceApi/create_routes.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Route configuration and factory module.
|
||||
Handles dynamic route creation based on configurations.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||
from Events.Engine.set_defaults.setClusters import (
|
||||
PrepareRouting,
|
||||
SetItems2Redis,
|
||||
PrepareEvents,
|
||||
)
|
||||
|
||||
|
||||
routers: Optional[PrepareRouting] = None
|
||||
|
||||
|
||||
def get_all_routers() -> PrepareRouting:
|
||||
"""
|
||||
Get all routers and protected routes from route configurations.
|
||||
|
||||
Returns:
|
||||
tuple: PrepareRouting
|
||||
"""
|
||||
global routers
|
||||
if routers:
|
||||
return routers
|
||||
|
||||
cluster_list = get_cluster_controller_group()
|
||||
routers = PrepareRouting(cluster_controller_group=cluster_list)
|
||||
return routers
|
||||
|
||||
|
||||
# async def health_check(request: Request):
|
||||
# """Default health check endpoint."""
|
||||
# return {"status": "healthy", "message": "Service is running"}
|
||||
#
|
||||
#
|
||||
# async def ping_test(request: Request, service_name: str = "base-router"):
|
||||
# """Default ping test endpoint."""
|
||||
# return {"ping": "pong", "service": service_name}
|
||||
11
DockerApiServices/AuthServiceApi/events_file.py
Normal file
11
DockerApiServices/AuthServiceApi/events_file.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import Events.AllEvents.authentication as auths_events
|
||||
|
||||
|
||||
events_list = (auths_events,)
|
||||
|
||||
|
||||
def retrieve_cluster_by_name(cluster_name: str):
|
||||
for module in events_list:
|
||||
if hasattr(module, cluster_name):
|
||||
return getattr(module, cluster_name, None)
|
||||
return
|
||||
256
DockerApiServices/AuthServiceApi/open_api_creator.py
Normal file
256
DockerApiServices/AuthServiceApi/open_api_creator.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""
|
||||
OpenAPI Schema Creator Module
|
||||
|
||||
This module provides functionality to create and customize OpenAPI documentation:
|
||||
- Custom security schemes (Bearer Auth, API Key)
|
||||
- Response schemas and examples
|
||||
- Tag management and descriptions
|
||||
- Error responses and validation
|
||||
- Custom documentation extensions
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
from fastapi import FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from create_routes import get_all_routers
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
class OpenAPISchemaCreator:
|
||||
"""
|
||||
OpenAPI schema creator and customizer for FastAPI applications.
|
||||
"""
|
||||
|
||||
def __init__(self, app: FastAPI):
|
||||
"""
|
||||
Initialize the OpenAPI schema creator.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
self.app = app
|
||||
self.cluster = get_all_routers()
|
||||
self.safe_endpoint_list = (
|
||||
self.cluster.safe_endpoints
|
||||
if hasattr(self.cluster, "safe_endpoints")
|
||||
else []
|
||||
)
|
||||
|
||||
def _create_security_schemes(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create security scheme definitions.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Security scheme configurations
|
||||
"""
|
||||
from ApiLayers.AllConfigs.Token.config import Auth
|
||||
|
||||
return {
|
||||
"BearerAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": Auth.ACCESS_TOKEN_TAG,
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
|
||||
def _create_common_responses(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create common response schemas.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Common response configurations
|
||||
"""
|
||||
return {
|
||||
"401": {
|
||||
"description": "Unauthorized - Invalid or missing credentials",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - Insufficient permissions",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {"type": "string"},
|
||||
"error_code": {"type": "string"},
|
||||
},
|
||||
},
|
||||
"example": {
|
||||
"detail": "Internal server error occurred",
|
||||
"error_code": "INTERNAL_ERROR",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _process_request_body(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process request body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "requestBody" in route_schema:
|
||||
request_body = route_schema["requestBody"]
|
||||
if "content" in request_body:
|
||||
content = request_body["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema["example"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _process_response_examples(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process response body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "responses" in route_schema:
|
||||
responses = route_schema["responses"]
|
||||
if "200" in responses:
|
||||
response = responses["200"]
|
||||
if "content" in response:
|
||||
content = response["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema[
|
||||
"example"
|
||||
]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def configure_route_security(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Configure security requirements for a specific route.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
if not schema.get("paths", {}).get(path, {}).get(method):
|
||||
return
|
||||
|
||||
# Check if endpoint is in safe list
|
||||
endpoint_path = f"{path}:{method}"
|
||||
if endpoint_path not in [
|
||||
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
|
||||
]:
|
||||
if "security" not in schema["paths"][path][method]:
|
||||
schema["paths"][path][method]["security"] = []
|
||||
schema["paths"][path][method]["security"].append({"BearerAuth": []})
|
||||
|
||||
def create_schema(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create the complete OpenAPI schema.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
openapi_schema = get_openapi(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
version="1.1.1",
|
||||
routes=self.app.routes,
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
if "components" not in openapi_schema:
|
||||
openapi_schema["components"] = {}
|
||||
|
||||
openapi_schema["components"][
|
||||
"securitySchemes"
|
||||
] = self._create_security_schemes()
|
||||
|
||||
# Configure route security and responses
|
||||
for route in self.app.routes:
|
||||
if isinstance(route, APIRoute) and route.include_in_schema:
|
||||
path = str(route.path)
|
||||
methods = [method.lower() for method in route.methods]
|
||||
for method in methods:
|
||||
self.configure_route_security(path, method, openapi_schema)
|
||||
|
||||
# Add custom documentation extensions
|
||||
openapi_schema["x-documentation"] = {
|
||||
"postman_collection": "/docs/postman",
|
||||
"swagger_ui": "/docs",
|
||||
"redoc": "/redoc",
|
||||
}
|
||||
return openapi_schema
|
||||
|
||||
|
||||
def create_openapi_schema(app: FastAPI) -> Dict[str, Any]:
|
||||
"""
|
||||
Create OpenAPI schema for a FastAPI application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
creator = OpenAPISchemaCreator(app)
|
||||
return creator.create_schema()
|
||||
15
DockerApiServices/AuthServiceApi/requirements.txt
Normal file
15
DockerApiServices/AuthServiceApi/requirements.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
fastapi==0.104.1
|
||||
uvicorn==0.24.0.post1
|
||||
pydantic==2.10.5
|
||||
sqlalchemy==2.0.37
|
||||
psycopg2-binary==2.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
motor==3.3.2
|
||||
redis==5.2.1
|
||||
pytest==7.4.4
|
||||
pytest-asyncio==0.21.2
|
||||
pytest-cov==4.1.0
|
||||
coverage==7.6.10
|
||||
arrow==1.3.0
|
||||
redmail==0.6.0
|
||||
sqlalchemy-mixins==2.0.5
|
||||
40
DockerApiServices/EventServiceApi/Dockerfile
Normal file
40
DockerApiServices/EventServiceApi/Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies and Poetry
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir poetry
|
||||
|
||||
# Copy Poetry configuration
|
||||
COPY DockerApiServices/pyproject.toml ./pyproject.toml
|
||||
|
||||
# Configure Poetry and install dependencies with optimizations
|
||||
RUN poetry config virtualenvs.create false \
|
||||
&& poetry install --no-interaction --no-ansi --no-root --only main \
|
||||
&& pip cache purge \
|
||||
&& rm -rf ~/.cache/pypoetry
|
||||
|
||||
# Copy application code
|
||||
COPY DockerApiServices/EventServiceApi /app
|
||||
|
||||
# Copy application code
|
||||
COPY ApiLayers /app/ApiLayers
|
||||
COPY Services /app/Services
|
||||
|
||||
# Events
|
||||
COPY Events/Engine /app/Events/Engine
|
||||
COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
COPY Events/AllEvents/events /app/Events/AllEvents/events
|
||||
COPY DockerApiServices/EventServiceApi/events_file.py /app/Events/AllEvents/events_file.py
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/app \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Run the application using the configured uvicorn server
|
||||
CMD ["poetry", "run", "python", "app.py"]
|
||||
27
DockerApiServices/EventServiceApi/app.py
Normal file
27
DockerApiServices/EventServiceApi/app.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
FastAPI Application Entry Point
|
||||
|
||||
This module initializes and configures the FastAPI application with:
|
||||
- CORS middleware for cross-origin requests
|
||||
- Request timing middleware for performance monitoring
|
||||
- Custom exception handlers for consistent error responses
|
||||
- Prometheus instrumentation for metrics
|
||||
- API routers for endpoint organization
|
||||
"""
|
||||
|
||||
import uvicorn
|
||||
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
from app_handler import setup_middleware
|
||||
from create_file import create_app
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
app = create_app() # Initialize FastAPI application
|
||||
Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics
|
||||
setup_middleware(app) # Configure middleware and exception handlers
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the application with Uvicorn
|
||||
uvicorn.Server(uvicorn.Config(**ApiConfig.as_dict())).run()
|
||||
82
DockerApiServices/EventServiceApi/app_handler.py
Normal file
82
DockerApiServices/EventServiceApi/app_handler.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
FastAPI Application Handler Module
|
||||
|
||||
This module contains all the handler functions for configuring and setting up the FastAPI application:
|
||||
- CORS middleware configuration
|
||||
- Exception handlers setup
|
||||
- Uvicorn server configuration
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI, Request, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
|
||||
from ApiLayers.Middleware.auth_middleware import (
|
||||
RequestTimingMiddleware,
|
||||
LoggerTimingMiddleware,
|
||||
)
|
||||
|
||||
|
||||
def setup_cors_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure CORS middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
||||
"""
|
||||
Handle generic exceptions and return formatted error responses.
|
||||
|
||||
Args:
|
||||
request: FastAPI request object
|
||||
exc: Exception instance
|
||||
|
||||
Returns:
|
||||
JSONResponse: Formatted error response
|
||||
"""
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content={"detail": "Internal server error", "error_code": "INTERNAL_ERROR"},
|
||||
)
|
||||
|
||||
|
||||
def setup_exception_handlers(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure custom exception handlers for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
|
||||
HTTPExceptionApiHandler,
|
||||
)
|
||||
|
||||
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
|
||||
app.add_exception_handler(
|
||||
HTTPExceptionApi, custom_exception_handler.handle_exception
|
||||
)
|
||||
app.add_exception_handler(Exception, generic_exception_handler)
|
||||
|
||||
|
||||
def setup_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure all middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
setup_cors_middleware(app)
|
||||
app.add_middleware(RequestTimingMiddleware)
|
||||
app.add_middleware(LoggerTimingMiddleware)
|
||||
setup_exception_handlers(app)
|
||||
59
DockerApiServices/EventServiceApi/config.py
Normal file
59
DockerApiServices/EventServiceApi/config.py
Normal file
@@ -0,0 +1,59 @@
|
||||
class DefaultApiConfig:
|
||||
app: str
|
||||
host: str
|
||||
port: int
|
||||
log_level: str
|
||||
reload: bool
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return {
|
||||
"app": cls.app,
|
||||
"host": cls.host,
|
||||
"port": int(cls.port),
|
||||
"log_level": cls.log_level,
|
||||
"reload": bool(cls.reload),
|
||||
}
|
||||
|
||||
|
||||
class ApiStatic:
|
||||
PLACEHOLDER = "https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg"
|
||||
FORGOT_LINK = "https://www.evyos.com.tr/password/create?tokenUrl="
|
||||
BLACKLIST_LINK = "https://www.evyos.com.tr/support/unknown-login-notice/"
|
||||
APP_DIR = "/home/berkay/git-evyos/api-managment-backend/"
|
||||
|
||||
@classmethod
|
||||
def forgot_link(cls, forgot_key):
|
||||
return cls.FORGOT_LINK + forgot_key
|
||||
|
||||
@classmethod
|
||||
def blacklist_login(cls, record_id):
|
||||
return cls.BLACKLIST_LINK + record_id
|
||||
|
||||
|
||||
class ApiConfig(DefaultApiConfig):
|
||||
# Api configuration
|
||||
APP_NAME = "evyos-event-api-gateway"
|
||||
TITLE = "WAG API Event Api Gateway"
|
||||
DESCRIPTION = (
|
||||
"This api is serves as web event api gateway only to evyos web services."
|
||||
)
|
||||
APP_URL = "https://www.event.eys.gen.tr"
|
||||
|
||||
# Uvicorn server configuration
|
||||
app = "app:app"
|
||||
host = "0.0.0.0"
|
||||
port = 41576
|
||||
log_level = "info"
|
||||
reload = True
|
||||
|
||||
|
||||
class MainConfig:
|
||||
# Date and Time Configuration
|
||||
DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss Z"
|
||||
DATETIME_FORMAT_JS = "YYYY-MM-DD HH:mm:ss +0"
|
||||
|
||||
# Timezone Configuration
|
||||
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
|
||||
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
|
||||
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones
|
||||
48
DockerApiServices/EventServiceApi/create_file.py
Normal file
48
DockerApiServices/EventServiceApi/create_file.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
FastAPI Application Factory Module
|
||||
|
||||
This module provides functionality to create and configure a FastAPI application with:
|
||||
- Custom OpenAPI schema configuration
|
||||
- Security scheme configuration for Bearer authentication
|
||||
- Automatic router registration
|
||||
- Response class configuration
|
||||
- Security requirements for protected endpoints
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from config import ApiConfig
|
||||
from create_routes import get_all_routers
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
Create and configure a FastAPI application with dynamic route creation.
|
||||
|
||||
Returns:
|
||||
FastAPI: Configured FastAPI application instance
|
||||
"""
|
||||
|
||||
from open_api_creator import create_openapi_schema
|
||||
|
||||
app = FastAPI(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
default_response_class=JSONResponse,
|
||||
) # Initialize FastAPI app
|
||||
|
||||
@app.get("/", include_in_schema=False, summary=str(ApiConfig.DESCRIPTION))
|
||||
def home() -> RedirectResponse:
|
||||
"""Redirect root path to API documentation."""
|
||||
return RedirectResponse(url="/docs")
|
||||
|
||||
# Get all routers and protected routes using the dynamic route creation
|
||||
prepare_routing = get_all_routers()
|
||||
|
||||
# Include all routers
|
||||
for router in prepare_routing.routers:
|
||||
app.include_router(router)
|
||||
|
||||
app.openapi = lambda app=app: create_openapi_schema(app)
|
||||
return app
|
||||
42
DockerApiServices/EventServiceApi/create_routes.py
Normal file
42
DockerApiServices/EventServiceApi/create_routes.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Route configuration and factory module.
|
||||
Handles dynamic route creation based on configurations.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||
from Events.Engine.set_defaults.setClusters import (
|
||||
PrepareRouting,
|
||||
SetItems2Redis,
|
||||
PrepareEvents,
|
||||
)
|
||||
|
||||
|
||||
routers: Optional[PrepareRouting] = None
|
||||
|
||||
|
||||
def get_all_routers() -> PrepareRouting:
|
||||
"""
|
||||
Get all routers and protected routes from route configurations.
|
||||
|
||||
Returns:
|
||||
tuple: PrepareRouting
|
||||
"""
|
||||
global routers
|
||||
if routers:
|
||||
return routers
|
||||
|
||||
cluster_list = get_cluster_controller_group()
|
||||
routers = PrepareRouting(cluster_controller_group=cluster_list)
|
||||
return routers
|
||||
|
||||
|
||||
# async def health_check(request: Request):
|
||||
# """Default health check endpoint."""
|
||||
# return {"status": "healthy", "message": "Service is running"}
|
||||
#
|
||||
#
|
||||
# async def ping_test(request: Request, service_name: str = "base-router"):
|
||||
# """Default ping test endpoint."""
|
||||
# return {"ping": "pong", "service": service_name}
|
||||
11
DockerApiServices/EventServiceApi/events_file.py
Normal file
11
DockerApiServices/EventServiceApi/events_file.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import Events.AllEvents.events as events_events
|
||||
|
||||
|
||||
events_list = (events_events,)
|
||||
|
||||
|
||||
def retrieve_cluster_by_name(cluster_name: str):
|
||||
for module in events_list:
|
||||
if hasattr(module, cluster_name):
|
||||
return getattr(module, cluster_name, None)
|
||||
return
|
||||
256
DockerApiServices/EventServiceApi/open_api_creator.py
Normal file
256
DockerApiServices/EventServiceApi/open_api_creator.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""
|
||||
OpenAPI Schema Creator Module
|
||||
|
||||
This module provides functionality to create and customize OpenAPI documentation:
|
||||
- Custom security schemes (Bearer Auth, API Key)
|
||||
- Response schemas and examples
|
||||
- Tag management and descriptions
|
||||
- Error responses and validation
|
||||
- Custom documentation extensions
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
from fastapi import FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from create_routes import get_all_routers
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
class OpenAPISchemaCreator:
|
||||
"""
|
||||
OpenAPI schema creator and customizer for FastAPI applications.
|
||||
"""
|
||||
|
||||
def __init__(self, app: FastAPI):
|
||||
"""
|
||||
Initialize the OpenAPI schema creator.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
self.app = app
|
||||
self.cluster = get_all_routers()
|
||||
self.safe_endpoint_list = (
|
||||
self.cluster.safe_endpoints
|
||||
if hasattr(self.cluster, "safe_endpoints")
|
||||
else []
|
||||
)
|
||||
|
||||
def _create_security_schemes(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create security scheme definitions.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Security scheme configurations
|
||||
"""
|
||||
from ApiLayers.AllConfigs.Token.config import Auth
|
||||
|
||||
return {
|
||||
"BearerAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": Auth.ACCESS_TOKEN_TAG,
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
|
||||
def _create_common_responses(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create common response schemas.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Common response configurations
|
||||
"""
|
||||
return {
|
||||
"401": {
|
||||
"description": "Unauthorized - Invalid or missing credentials",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - Insufficient permissions",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {"type": "string"},
|
||||
"error_code": {"type": "string"},
|
||||
},
|
||||
},
|
||||
"example": {
|
||||
"detail": "Internal server error occurred",
|
||||
"error_code": "INTERNAL_ERROR",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _process_request_body(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process request body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "requestBody" in route_schema:
|
||||
request_body = route_schema["requestBody"]
|
||||
if "content" in request_body:
|
||||
content = request_body["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema["example"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _process_response_examples(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process response body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "responses" in route_schema:
|
||||
responses = route_schema["responses"]
|
||||
if "200" in responses:
|
||||
response = responses["200"]
|
||||
if "content" in response:
|
||||
content = response["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema[
|
||||
"example"
|
||||
]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def configure_route_security(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Configure security requirements for a specific route.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
if not schema.get("paths", {}).get(path, {}).get(method):
|
||||
return
|
||||
|
||||
# Check if endpoint is in safe list
|
||||
endpoint_path = f"{path}:{method}"
|
||||
if endpoint_path not in [
|
||||
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
|
||||
]:
|
||||
if "security" not in schema["paths"][path][method]:
|
||||
schema["paths"][path][method]["security"] = []
|
||||
schema["paths"][path][method]["security"].append({"BearerAuth": []})
|
||||
|
||||
def create_schema(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create the complete OpenAPI schema.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
openapi_schema = get_openapi(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
version="1.1.1",
|
||||
routes=self.app.routes,
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
if "components" not in openapi_schema:
|
||||
openapi_schema["components"] = {}
|
||||
|
||||
openapi_schema["components"][
|
||||
"securitySchemes"
|
||||
] = self._create_security_schemes()
|
||||
|
||||
# Configure route security and responses
|
||||
for route in self.app.routes:
|
||||
if isinstance(route, APIRoute) and route.include_in_schema:
|
||||
path = str(route.path)
|
||||
methods = [method.lower() for method in route.methods]
|
||||
for method in methods:
|
||||
self.configure_route_security(path, method, openapi_schema)
|
||||
|
||||
# Add custom documentation extensions
|
||||
openapi_schema["x-documentation"] = {
|
||||
"postman_collection": "/docs/postman",
|
||||
"swagger_ui": "/docs",
|
||||
"redoc": "/redoc",
|
||||
}
|
||||
return openapi_schema
|
||||
|
||||
|
||||
def create_openapi_schema(app: FastAPI) -> Dict[str, Any]:
|
||||
"""
|
||||
Create OpenAPI schema for a FastAPI application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
creator = OpenAPISchemaCreator(app)
|
||||
return creator.create_schema()
|
||||
40
DockerApiServices/InitServiceApi/Dockerfile
Normal file
40
DockerApiServices/InitServiceApi/Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies and Poetry
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir poetry
|
||||
|
||||
# Copy Poetry configuration
|
||||
COPY DockerApiServices/pyproject.toml ./pyproject.toml
|
||||
|
||||
# Configure Poetry and install dependencies with optimizations
|
||||
RUN poetry config virtualenvs.create false \
|
||||
&& poetry install --no-interaction --no-ansi --no-root --only main \
|
||||
&& pip cache purge \
|
||||
&& rm -rf ~/.cache/pypoetry
|
||||
|
||||
# Copy application code
|
||||
COPY DockerApiServices/InitServiceApi /app
|
||||
|
||||
# Copy application code
|
||||
COPY ApiLayers /app/ApiLayers
|
||||
COPY Services /app/Services
|
||||
|
||||
# Events
|
||||
# COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
COPY Events/Engine /app/Events/Engine
|
||||
COPY Events/AllEvents /app/Events/AllEvents
|
||||
COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/app \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Run the application using the configured uvicorn server
|
||||
CMD ["poetry", "run", "python", "app.py"]
|
||||
5
DockerApiServices/InitServiceApi/app.py
Normal file
5
DockerApiServices/InitServiceApi/app.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from create_all_dependecies import SetRedisDefaults
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
SetRedisDefaults.set_all()
|
||||
77
DockerApiServices/InitServiceApi/config.py
Normal file
77
DockerApiServices/InitServiceApi/config.py
Normal file
@@ -0,0 +1,77 @@
|
||||
class DefaultApiConfig:
|
||||
app: str
|
||||
host: str
|
||||
port: int
|
||||
log_level: str
|
||||
reload: bool
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return {
|
||||
"app": cls.app,
|
||||
"host": cls.host,
|
||||
"port": int(cls.port),
|
||||
"log_level": cls.log_level,
|
||||
"reload": bool(cls.reload),
|
||||
}
|
||||
|
||||
|
||||
class ApiStatic:
|
||||
PLACEHOLDER = "https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg"
|
||||
FORGOT_LINK = "https://www.evyos.com.tr/password/create?tokenUrl="
|
||||
BLACKLIST_LINK = "https://www.evyos.com.tr/support/unknown-login-notice/"
|
||||
APP_DIR = "/home/berkay/git-evyos/api-managment-backend/"
|
||||
|
||||
@classmethod
|
||||
def forgot_link(cls, forgot_key):
|
||||
return cls.FORGOT_LINK + forgot_key
|
||||
|
||||
@classmethod
|
||||
def blacklist_login(cls, record_id):
|
||||
return cls.BLACKLIST_LINK + record_id
|
||||
|
||||
|
||||
class HostConfig:
|
||||
MAIN_HOST = "10.10.2.36" # http://10.10.2.36
|
||||
EMAIL_HOST = "10.10.2.34" # http://10.10.2.34
|
||||
|
||||
|
||||
class ApiConfig(DefaultApiConfig):
|
||||
# Application Information
|
||||
APP_NAME = "evyos-auth-api-gateway"
|
||||
TITLE = "WAG API Auth Api Gateway"
|
||||
DESCRIPTION = (
|
||||
"This api is serves as web auth api gateway only to evyos web services."
|
||||
)
|
||||
APP_URL = "https://www.auth.eys.gen.tr"
|
||||
|
||||
# Server Configuration
|
||||
app = "app:app"
|
||||
host = "0.0.0.0"
|
||||
port = 41575
|
||||
log_level = "info"
|
||||
reload = True
|
||||
|
||||
|
||||
class MainConfig:
|
||||
|
||||
# Date and Time Configuration
|
||||
DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss Z"
|
||||
DATETIME_FORMAT_JS = "YYYY-MM-DD HH:mm:ss +0"
|
||||
|
||||
# Timezone Configuration
|
||||
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
|
||||
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
|
||||
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones
|
||||
|
||||
|
||||
class LanguageConfig:
|
||||
|
||||
SUPPORTED_LANGUAGES = ["en", "tr"]
|
||||
DEFAULT_LANGUAGE = "tr"
|
||||
|
||||
|
||||
class ValidationsConfig:
|
||||
|
||||
SUPPORTED_VALIDATIONS = ["header", "validation", "all"]
|
||||
DEFAULT_VALIDATION = "all"
|
||||
45
DockerApiServices/InitServiceApi/create_all_dependecies.py
Normal file
45
DockerApiServices/InitServiceApi/create_all_dependecies.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
Route configuration and factory module.
|
||||
Handles dynamic route creation based on configurations.
|
||||
"""
|
||||
|
||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||
from Events.Engine.set_defaults.setClusters import SetItems2Redis, PrepareEvents
|
||||
|
||||
from ApiLayers.LanguageModels.set_defaults.language_setters import (
|
||||
SetClusterLanguageModelsRedis,
|
||||
SetDefaultLanguageModelsRedis,
|
||||
)
|
||||
from ApiLayers.LanguageModels.Response.all_responses import all_response_list
|
||||
from ApiLayers.LanguageModels.Errors.all_errors import all_errors_list
|
||||
|
||||
|
||||
class SetRedisDefaults:
|
||||
|
||||
@classmethod
|
||||
def set_all(cls) -> None:
|
||||
"""
|
||||
Get all routers and protected routes from route configurations.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
cluster_list = get_cluster_controller_group()
|
||||
default_dict = dict(
|
||||
set_response_languages_list=all_response_list,
|
||||
set_errors_languages_list=all_errors_list,
|
||||
)
|
||||
prepare_events = PrepareEvents(cluster_controller_group=cluster_list)
|
||||
SetItems2Redis(prepare_events=prepare_events)
|
||||
SetDefaultLanguageModelsRedis(**default_dict).set_all()
|
||||
SetClusterLanguageModelsRedis(cluster_controller_group=cluster_list).set_all()
|
||||
|
||||
|
||||
# async def health_check(request: Request):
|
||||
# """Default health check endpoint."""
|
||||
# return {"status": "healthy", "message": "Service is running"}
|
||||
#
|
||||
#
|
||||
# async def ping_test(request: Request, service_name: str = "base-router"):
|
||||
# """Default ping test endpoint."""
|
||||
# return {"ping": "pong", "service": service_name}
|
||||
57
DockerApiServices/README.md
Normal file
57
DockerApiServices/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Docker Services Guide
|
||||
|
||||
This repository contains multiple microservices that can be run using Docker Compose.
|
||||
|
||||
## Quick Start (With Cache)
|
||||
For regular development when dependencies haven't changed:
|
||||
```bash
|
||||
# Build and run Auth Service
|
||||
docker compose -f docker-compose-services.yml up auth-service
|
||||
|
||||
# Build and run Event Service
|
||||
docker compose -f docker-compose-services.yml up event-service
|
||||
|
||||
# Build and run Validation Service
|
||||
docker compose -f docker-compose-services.yml up validation-service
|
||||
|
||||
# Build and run all services
|
||||
docker compose -f docker-compose-services.yml up
|
||||
```
|
||||
|
||||
## Clean Build (No Cache)
|
||||
Use these commands when changing Dockerfile or dependencies:
|
||||
```bash
|
||||
# Auth Service
|
||||
docker compose -f docker-compose-services.yml build --no-cache auth-service && docker compose -f docker-compose-services.yml up auth-service
|
||||
|
||||
# Event Service
|
||||
docker compose -f docker-compose-services.yml build --no-cache event-service && docker compose -f docker-compose-services.yml up event-service
|
||||
|
||||
# Validation Service
|
||||
docker compose -f docker-compose-services.yml build --no-cache validation-service && docker compose -f docker-compose-services.yml up validation-service
|
||||
|
||||
# All Services
|
||||
docker compose -f docker-compose-services.yml build --no-cache && docker compose -f docker-compose-services.yml up
|
||||
```
|
||||
|
||||
## Service Ports
|
||||
- Auth Service: http://localhost:41575
|
||||
- Event Service: http://localhost:41576
|
||||
- Validation Service: http://localhost:41577
|
||||
|
||||
## Development Notes
|
||||
- Use clean build (--no-cache) when:
|
||||
- Changing Dockerfile
|
||||
- Updating dependencies
|
||||
- Experiencing caching issues
|
||||
- Use regular build (with cache) when:
|
||||
- Only changing application code
|
||||
- For faster development iterations
|
||||
- Run in detached mode:
|
||||
```bash
|
||||
docker compose -f docker-compose-services.yml up -d auth-service
|
||||
```
|
||||
- Stop services:
|
||||
```bash
|
||||
docker compose -f docker-compose-services.yml down
|
||||
```
|
||||
44
DockerApiServices/ValidationServiceApi/Dockerfile
Normal file
44
DockerApiServices/ValidationServiceApi/Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies and Poetry
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir poetry
|
||||
|
||||
# Copy Poetry configuration
|
||||
COPY DockerApiServices/pyproject.toml ./pyproject.toml
|
||||
|
||||
# Configure Poetry and install dependencies with optimizations
|
||||
RUN poetry config virtualenvs.create false \
|
||||
&& poetry install --no-interaction --no-ansi --no-root --only main \
|
||||
&& pip cache purge \
|
||||
&& rm -rf ~/.cache/pypoetry
|
||||
|
||||
# Copy application code
|
||||
COPY DockerApiServices/ValidationServiceApi /app
|
||||
|
||||
# Copy application code
|
||||
COPY ApiLayers /app/ApiLayers
|
||||
COPY Services /app/Services
|
||||
|
||||
# Events
|
||||
# COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
COPY Events/Engine /app/Events/Engine
|
||||
COPY Events/AllEvents/validations /app/Events/AllEvents/validations
|
||||
COPY Events/base_request_model.py /app/Events/base_request_model.py
|
||||
COPY DockerApiServices/ValidationServiceApi/events_file.py /app/Events/AllEvents/events_file.py
|
||||
|
||||
COPY Events/AllEvents /app/Events/JustEvents
|
||||
COPY Events/AllEvents/just_events_file.py /app/Events/JustEvents/events_file.py
|
||||
|
||||
# Set Python path to include app directory
|
||||
ENV PYTHONPATH=/app \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Run the application using the configured uvicorn server
|
||||
CMD ["poetry", "run", "python", "app.py"]
|
||||
27
DockerApiServices/ValidationServiceApi/app.py
Normal file
27
DockerApiServices/ValidationServiceApi/app.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
FastAPI Application Entry Point
|
||||
|
||||
This module initializes and configures the FastAPI application with:
|
||||
- CORS middleware for cross-origin requests
|
||||
- Request timing middleware for performance monitoring
|
||||
- Custom exception handlers for consistent error responses
|
||||
- Prometheus instrumentation for metrics
|
||||
- API routers for endpoint organization
|
||||
"""
|
||||
|
||||
import uvicorn
|
||||
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
from app_handler import setup_middleware
|
||||
from create_file import create_app
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
app = create_app() # Initialize FastAPI application
|
||||
Instrumentator().instrument(app=app).expose(app=app) # Setup Prometheus metrics
|
||||
setup_middleware(app) # Configure middleware and exception handlers
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the application with Uvicorn
|
||||
uvicorn.Server(uvicorn.Config(**ApiConfig.as_dict())).run()
|
||||
82
DockerApiServices/ValidationServiceApi/app_handler.py
Normal file
82
DockerApiServices/ValidationServiceApi/app_handler.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
FastAPI Application Handler Module
|
||||
|
||||
This module contains all the handler functions for configuring and setting up the FastAPI application:
|
||||
- CORS middleware configuration
|
||||
- Exception handlers setup
|
||||
- Uvicorn server configuration
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI, Request, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from ApiLayers.ErrorHandlers.Exceptions.api_exc import HTTPExceptionApi
|
||||
from ApiLayers.Middleware.auth_middleware import (
|
||||
RequestTimingMiddleware,
|
||||
LoggerTimingMiddleware,
|
||||
)
|
||||
|
||||
|
||||
def setup_cors_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure CORS middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
||||
"""
|
||||
Handle generic exceptions and return formatted error responses.
|
||||
|
||||
Args:
|
||||
request: FastAPI request object
|
||||
exc: Exception instance
|
||||
|
||||
Returns:
|
||||
JSONResponse: Formatted error response
|
||||
"""
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content={"detail": "Internal server error", "error_code": "INTERNAL_ERROR"},
|
||||
)
|
||||
|
||||
|
||||
def setup_exception_handlers(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure custom exception handlers for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
from ApiLayers.ErrorHandlers.ErrorHandlers.api_exc_handler import (
|
||||
HTTPExceptionApiHandler,
|
||||
)
|
||||
|
||||
custom_exception_handler = HTTPExceptionApiHandler(response_model=JSONResponse)
|
||||
app.add_exception_handler(
|
||||
HTTPExceptionApi, custom_exception_handler.handle_exception
|
||||
)
|
||||
app.add_exception_handler(Exception, generic_exception_handler)
|
||||
|
||||
|
||||
def setup_middleware(app: FastAPI) -> None:
|
||||
"""
|
||||
Configure all middleware for the application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
setup_cors_middleware(app)
|
||||
app.add_middleware(RequestTimingMiddleware)
|
||||
app.add_middleware(LoggerTimingMiddleware)
|
||||
setup_exception_handlers(app)
|
||||
64
DockerApiServices/ValidationServiceApi/config.py
Normal file
64
DockerApiServices/ValidationServiceApi/config.py
Normal file
@@ -0,0 +1,64 @@
|
||||
class DefaultApiConfig:
|
||||
app: str
|
||||
host: str
|
||||
port: int
|
||||
log_level: str
|
||||
reload: bool
|
||||
|
||||
@classmethod
|
||||
def as_dict(cls):
|
||||
return {
|
||||
"app": cls.app,
|
||||
"host": cls.host,
|
||||
"port": int(cls.port),
|
||||
"log_level": cls.log_level,
|
||||
"reload": bool(cls.reload),
|
||||
}
|
||||
|
||||
|
||||
class ApiStatic:
|
||||
PLACEHOLDER = "https://s.tmimgcdn.com/scr/800x500/276800/building-home-nature-logo-vector-template-3_276851-original.jpg"
|
||||
FORGOT_LINK = "https://www.evyos.com.tr/password/create?tokenUrl="
|
||||
BLACKLIST_LINK = "https://www.evyos.com.tr/support/unknown-login-notice/"
|
||||
APP_DIR = "/home/berkay/git-evyos/api-managment-backend/"
|
||||
|
||||
@classmethod
|
||||
def forgot_link(cls, forgot_key):
|
||||
return cls.FORGOT_LINK + forgot_key
|
||||
|
||||
@classmethod
|
||||
def blacklist_login(cls, record_id):
|
||||
return cls.BLACKLIST_LINK + record_id
|
||||
|
||||
|
||||
class ApiConfig(DefaultApiConfig):
|
||||
# Api configuration
|
||||
APP_NAME = "evyos-validation-api-gateway"
|
||||
TITLE = "WAG API Validation Api Gateway"
|
||||
DESCRIPTION = (
|
||||
"This api is serves as web validation api gateway only to evyos web services."
|
||||
)
|
||||
APP_URL = "https://www.validation.eys.gen.tr"
|
||||
# App configuration
|
||||
app = "app:app"
|
||||
host = "0.0.0.0"
|
||||
port = 41577
|
||||
log_level = "info"
|
||||
reload = True
|
||||
|
||||
|
||||
class MainConfig:
|
||||
# Main configuration
|
||||
DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss Z"
|
||||
DATETIME_FORMAT_JS = "YYYY-MM-DD HH:mm:ss +0"
|
||||
|
||||
# Timezone Configuration
|
||||
DEFAULT_TIMEZONE = "GMT+3" # Default timezone for the application
|
||||
SYSTEM_TIMEZONE = "GMT+0" # System timezone (used for internal operations)
|
||||
SUPPORTED_TIMEZONES = ["GMT+0", "GMT+3"] # List of supported timezones
|
||||
|
||||
|
||||
class ValidationsConfig:
|
||||
|
||||
SUPPORTED_VALIDATIONS = ["header", "validation", "all"]
|
||||
DEFAULT_VALIDATION = "all"
|
||||
48
DockerApiServices/ValidationServiceApi/create_file.py
Normal file
48
DockerApiServices/ValidationServiceApi/create_file.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
FastAPI Application Factory Module
|
||||
|
||||
This module provides functionality to create and configure a FastAPI application with:
|
||||
- Custom OpenAPI schema configuration
|
||||
- Security scheme configuration for Bearer authentication
|
||||
- Automatic router registration
|
||||
- Response class configuration
|
||||
- Security requirements for protected endpoints
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from config import ApiConfig
|
||||
from create_routes import get_all_routers
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
Create and configure a FastAPI application with dynamic route creation.
|
||||
|
||||
Returns:
|
||||
FastAPI: Configured FastAPI application instance
|
||||
"""
|
||||
|
||||
from open_api_creator import create_openapi_schema
|
||||
|
||||
app = FastAPI(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
default_response_class=JSONResponse,
|
||||
) # Initialize FastAPI app
|
||||
|
||||
@app.get("/", include_in_schema=False, summary=str(ApiConfig.DESCRIPTION))
|
||||
def home() -> RedirectResponse:
|
||||
"""Redirect root path to API documentation."""
|
||||
return RedirectResponse(url="/docs")
|
||||
|
||||
# Get all routers and protected routes using the dynamic route creation
|
||||
prepare_routing = get_all_routers()
|
||||
|
||||
# Include all routers
|
||||
for router in prepare_routing.routers:
|
||||
app.include_router(router)
|
||||
|
||||
app.openapi = lambda app=app: create_openapi_schema(app)
|
||||
return app
|
||||
42
DockerApiServices/ValidationServiceApi/create_routes.py
Normal file
42
DockerApiServices/ValidationServiceApi/create_routes.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Route configuration and factory module.
|
||||
Handles dynamic route creation based on configurations.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from Events.Engine.set_defaults.run import get_cluster_controller_group
|
||||
from Events.Engine.set_defaults.setClusters import (
|
||||
PrepareRouting,
|
||||
SetItems2Redis,
|
||||
PrepareEvents,
|
||||
)
|
||||
|
||||
|
||||
routers: Optional[PrepareRouting] = None
|
||||
|
||||
|
||||
def get_all_routers() -> PrepareRouting:
|
||||
"""
|
||||
Get all routers and protected routes from route configurations.
|
||||
|
||||
Returns:
|
||||
tuple: PrepareRouting
|
||||
"""
|
||||
global routers
|
||||
if routers:
|
||||
return routers
|
||||
|
||||
cluster_list = get_cluster_controller_group()
|
||||
routers = PrepareRouting(cluster_controller_group=cluster_list)
|
||||
return routers
|
||||
|
||||
|
||||
# async def health_check(request: Request):
|
||||
# """Default health check endpoint."""
|
||||
# return {"status": "healthy", "message": "Service is running"}
|
||||
#
|
||||
#
|
||||
# async def ping_test(request: Request, service_name: str = "base-router"):
|
||||
# """Default ping test endpoint."""
|
||||
# return {"ping": "pong", "service": service_name}
|
||||
10
DockerApiServices/ValidationServiceApi/events_file.py
Normal file
10
DockerApiServices/ValidationServiceApi/events_file.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import Events.AllEvents.validations as validations_events
|
||||
|
||||
events_list = (validations_events,)
|
||||
|
||||
|
||||
def retrieve_cluster_by_name(cluster_name: str):
|
||||
for module in events_list:
|
||||
if hasattr(module, cluster_name):
|
||||
return getattr(module, cluster_name, None)
|
||||
return
|
||||
256
DockerApiServices/ValidationServiceApi/open_api_creator.py
Normal file
256
DockerApiServices/ValidationServiceApi/open_api_creator.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""
|
||||
OpenAPI Schema Creator Module
|
||||
|
||||
This module provides functionality to create and customize OpenAPI documentation:
|
||||
- Custom security schemes (Bearer Auth, API Key)
|
||||
- Response schemas and examples
|
||||
- Tag management and descriptions
|
||||
- Error responses and validation
|
||||
- Custom documentation extensions
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
from fastapi import FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from create_routes import get_all_routers
|
||||
from config import ApiConfig
|
||||
|
||||
|
||||
class OpenAPISchemaCreator:
|
||||
"""
|
||||
OpenAPI schema creator and customizer for FastAPI applications.
|
||||
"""
|
||||
|
||||
def __init__(self, app: FastAPI):
|
||||
"""
|
||||
Initialize the OpenAPI schema creator.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
"""
|
||||
self.app = app
|
||||
self.cluster = get_all_routers()
|
||||
self.safe_endpoint_list = (
|
||||
self.cluster.safe_endpoints
|
||||
if hasattr(self.cluster, "safe_endpoints")
|
||||
else []
|
||||
)
|
||||
|
||||
def _create_security_schemes(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create security scheme definitions.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Security scheme configurations
|
||||
"""
|
||||
from ApiLayers.AllConfigs.Token.config import Auth
|
||||
|
||||
return {
|
||||
"BearerAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": Auth.ACCESS_TOKEN_TAG,
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
|
||||
def _create_common_responses(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create common response schemas.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Common response configurations
|
||||
"""
|
||||
return {
|
||||
"401": {
|
||||
"description": "Unauthorized - Invalid or missing credentials",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - Insufficient permissions",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/HTTPValidationError"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {"type": "string"},
|
||||
"error_code": {"type": "string"},
|
||||
},
|
||||
},
|
||||
"example": {
|
||||
"detail": "Internal server error occurred",
|
||||
"error_code": "INTERNAL_ERROR",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _process_request_body(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process request body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "requestBody" in route_schema:
|
||||
request_body = route_schema["requestBody"]
|
||||
if "content" in request_body:
|
||||
content = request_body["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema["example"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _process_response_examples(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Process response body to include examples from model config.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
try:
|
||||
route_schema = schema["paths"][path][method]
|
||||
if "responses" in route_schema:
|
||||
responses = route_schema["responses"]
|
||||
if "200" in responses:
|
||||
response = responses["200"]
|
||||
if "content" in response:
|
||||
content = response["content"]
|
||||
if "application/json" in content:
|
||||
json_content = content["application/json"]
|
||||
if (
|
||||
"schema" in json_content
|
||||
and "$ref" in json_content["schema"]
|
||||
):
|
||||
ref = json_content["schema"]["$ref"]
|
||||
model_name = ref.split("/")[-1]
|
||||
if model_name in schema["components"]["schemas"]:
|
||||
model_schema = schema["components"]["schemas"][
|
||||
model_name
|
||||
]
|
||||
if "example" in model_schema:
|
||||
json_content["example"] = model_schema[
|
||||
"example"
|
||||
]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def configure_route_security(
|
||||
self, path: str, method: str, schema: Dict[str, Any]
|
||||
) -> None:
|
||||
"""
|
||||
Configure security requirements for a specific route.
|
||||
|
||||
Args:
|
||||
path: Route path
|
||||
method: HTTP method
|
||||
schema: OpenAPI schema to modify
|
||||
"""
|
||||
if not schema.get("paths", {}).get(path, {}).get(method):
|
||||
return
|
||||
|
||||
# Check if endpoint is in safe list
|
||||
endpoint_path = f"{path}:{method}"
|
||||
if endpoint_path not in [
|
||||
f"{e.URL}:{e.METHOD.lower()}" for e in self.safe_endpoint_list
|
||||
]:
|
||||
if "security" not in schema["paths"][path][method]:
|
||||
schema["paths"][path][method]["security"] = []
|
||||
schema["paths"][path][method]["security"].append({"BearerAuth": []})
|
||||
|
||||
def create_schema(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Create the complete OpenAPI schema.
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
openapi_schema = get_openapi(
|
||||
title=ApiConfig.TITLE,
|
||||
description=ApiConfig.DESCRIPTION,
|
||||
version="1.1.1",
|
||||
routes=self.app.routes,
|
||||
)
|
||||
|
||||
# Add security schemes
|
||||
if "components" not in openapi_schema:
|
||||
openapi_schema["components"] = {}
|
||||
|
||||
openapi_schema["components"][
|
||||
"securitySchemes"
|
||||
] = self._create_security_schemes()
|
||||
|
||||
# Configure route security and responses
|
||||
for route in self.app.routes:
|
||||
if isinstance(route, APIRoute) and route.include_in_schema:
|
||||
path = str(route.path)
|
||||
methods = [method.lower() for method in route.methods]
|
||||
for method in methods:
|
||||
self.configure_route_security(path, method, openapi_schema)
|
||||
|
||||
# Add custom documentation extensions
|
||||
openapi_schema["x-documentation"] = {
|
||||
"postman_collection": "/docs/postman",
|
||||
"swagger_ui": "/docs",
|
||||
"redoc": "/redoc",
|
||||
}
|
||||
return openapi_schema
|
||||
|
||||
|
||||
def create_openapi_schema(app: FastAPI) -> Dict[str, Any]:
|
||||
"""
|
||||
Create OpenAPI schema for a FastAPI application.
|
||||
|
||||
Args:
|
||||
app: FastAPI application instance
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Complete OpenAPI schema
|
||||
"""
|
||||
creator = OpenAPISchemaCreator(app)
|
||||
return creator.create_schema()
|
||||
83
DockerApiServices/pyproject.toml
Normal file
83
DockerApiServices/pyproject.toml
Normal file
@@ -0,0 +1,83 @@
|
||||
[tool.poetry]
|
||||
name = "wag-management-api-services"
|
||||
version = "0.1.1"
|
||||
description = "WAG Management API Service"
|
||||
authors = ["Karatay Berkay <karatay.berkay@evyos.com.tr>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
# FastAPI and Web
|
||||
fastapi = "^0.104.1"
|
||||
uvicorn = "^0.24.0"
|
||||
pydantic = "^2.5.2"
|
||||
|
||||
# MongoDB
|
||||
motor = "3.3.2" # Pinned version
|
||||
pymongo = "4.5.0" # Pinned version to match motor
|
||||
|
||||
# PostgreSQL
|
||||
sqlalchemy = "^2.0.23"
|
||||
sqlalchemy-mixins = "^2.0.5"
|
||||
psycopg2-binary = "^2.9.9"
|
||||
|
||||
# Redis
|
||||
redis = "^5.0.1"
|
||||
arrow = "^1.3.0"
|
||||
|
||||
# Email
|
||||
redmail = "^0.6.0"
|
||||
|
||||
# Testing
|
||||
pytest = "^7.4.3"
|
||||
pytest-asyncio = "^0.21.1"
|
||||
pytest-cov = "^4.1.0"
|
||||
|
||||
# Monitoring
|
||||
prometheus-client = "^0.19.0"
|
||||
prometheus-fastapi-instrumentator = "^6.1.0"
|
||||
|
||||
# Cryptography
|
||||
cryptography = "^43.0.3"
|
||||
|
||||
# Utilities
|
||||
python-dateutil = "^2.8.2"
|
||||
typing-extensions = "^4.8.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.11.0"
|
||||
isort = "^5.12.0"
|
||||
mypy = "^1.7.1"
|
||||
flake8 = "^6.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
target-version = ['py39']
|
||||
include = '\.pyi?$'
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
force_grid_wrap = 0
|
||||
use_parentheses = true
|
||||
line_length = 88
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.9"
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = true
|
||||
check_untyped_defs = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "6.0"
|
||||
addopts = "-ra -q --cov=Services"
|
||||
testpaths = [
|
||||
"Ztest",
|
||||
]
|
||||
python_files = ["test_*.py"]
|
||||
asyncio_mode = "auto"
|
||||
17
DockerApiServices/requirements.txt
Normal file
17
DockerApiServices/requirements.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
fastapi==0.104.1
|
||||
uvicorn==0.24.0.post1
|
||||
pydantic==2.10.5
|
||||
sqlalchemy==2.0.37
|
||||
psycopg2-binary==2.9.10
|
||||
python-dateutil==2.9.0.post0
|
||||
motor==3.3.2
|
||||
redis==5.2.1
|
||||
pytest==7.4.4
|
||||
pytest-asyncio==0.21.2
|
||||
pytest-cov==4.1.0
|
||||
coverage==7.6.10
|
||||
arrow==1.3.0
|
||||
redmail==0.6.0
|
||||
sqlalchemy-mixins==2.0.5
|
||||
prometheus-client==0.19.0
|
||||
prometheus-fastapi-instrumentator==6.1.0
|
||||
29
DockerApiServices/steps.txt
Normal file
29
DockerApiServices/steps.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
WAG Management API Microservices Setup
|
||||
|
||||
1. Authentication Service (Port 8000)
|
||||
- User authentication and authorization
|
||||
- JWT token management
|
||||
- Role-based access control
|
||||
- Uses PostgreSQL for user data
|
||||
|
||||
2. Event Service (Port 8001)
|
||||
- Event processing and handling
|
||||
- Message queue integration
|
||||
- Real-time notifications
|
||||
- Uses MongoDB for event storage
|
||||
|
||||
3. Validation Service (Port 8002)
|
||||
- Request validation
|
||||
- Data sanitization
|
||||
- Schema validation
|
||||
- Uses Redis for caching
|
||||
|
||||
To run the services:
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
Access services at:
|
||||
- Auth Service: http://localhost:8000
|
||||
- Event Service: http://localhost:8001
|
||||
- Validation Service: http://localhost:8002
|
||||
Reference in New Issue
Block a user