Skip to content

Commit

Permalink
Add API endpoints for order management and integrate with main applic…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
beeguy74 committed Mar 7, 2025
1 parent 651033b commit 4e4d309
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 4 deletions.
51 changes: 51 additions & 0 deletions margin_app/app/api/order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
API endpoints for order management.
"""

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.crud.order import order_crud
from app.models.order import Order
from app.schemas.order import OrderCreate, OrderResponse

router = APIRouter()


@router.post(
"/create_order",
response_model=OrderResponse,
status_code=status.HTTP_201_CREATED,
summary="Create a new order",
description="Creates a new order in the system",
)
async def create_order(
order_data: OrderCreate,
db: AsyncSession = Depends(order_crud.session),
) -> Order:
"""
Create a new order with the provided order data.
Args:
order_data: The order data to create
order_crud: The OrderCRUD instance for database operations
Returns:
The created order
Raises:
HTTPException: If there's an error creating the order
"""
try:
order = await order_crud.add_new_order(
user_id=order_data.user_id,
price=order_data.price,
token=order_data.token,
position=order_data.position,
)
return order
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to create order: {str(e)}",
)
4 changes: 3 additions & 1 deletion margin_app/app/crud/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ async def execute_order(self, order_id: uuid.UUID) -> bool:
return False

# Order execution logic would go here
# This could include updating the order status, processing the transaction, etc.
logger.info(f"Order {order_id} executed successfully")
return True

except Exception as e:
logger.error(f"Failed to execute order {order_id}: {str(e)}")
return False


order_crud = OrderCRUD()
11 changes: 8 additions & 3 deletions margin_app/app/main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""
Main entry point for the application.
Main FastAPI application entry point.
"""

import sys

from fastapi import FastAPI, Request
from loguru import logger

from app.api.deposit import router as deposit_router
from app.api.liquidation import router as liquidation_router
from app.api.margin_position import router as margin_position_router
from app.api.order import router as order_router
from app.api.pools import router as pool_router
from app.api.user import router as user_router
from app.api.deposit import router as deposit_router

# Initialize FastAPI app
app = FastAPI(
Expand All @@ -28,6 +30,7 @@
)
app.include_router(user_router, prefix="/api/user", tags=["User"])
app.include_router(deposit_router, prefix="/api/deposit", tags=["Deposit"])
app.include_router(order_router, prefix="/api/order", tags=["Order"])

# Configure Loguru
logger.remove() # Remove default logger to configure custom settings
Expand All @@ -40,6 +43,7 @@
diagnose=True,
)


@app.on_event("startup")
async def startup_event():
"""
Expand All @@ -48,6 +52,7 @@ async def startup_event():
"""
logger.info("Application startup: Initializing resources.")


@app.on_event("shutdown")
async def shutdown_event():
"""
Expand All @@ -67,7 +72,7 @@ async def log_requests(request: Request, call_next):
logger.info(f"Response: {response.status_code} {request.url}")
return response


# Additional route
@app.get("/health")
async def health_check():
Expand Down
30 changes: 30 additions & 0 deletions margin_app/app/schemas/order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Pydantic schemas for order operations.
"""

import uuid

from pydantic import BaseModel, Field


class OrderCreate(BaseModel):
"""Schema for creating a new order"""

user_id: uuid.UUID = Field(..., description="ID of the user placing the order")
price: float = Field(..., description="Price of the order")
token: str = Field(..., description="Token symbol for the order")
position: uuid.UUID = Field(..., description="Position ID related to the order")


class OrderResponse(BaseModel):
"""Schema for order response"""

id: uuid.UUID
user_id: uuid.UUID
price: float
token: str
position: uuid.UUID

class Config:
"""Pydantic model configuration"""
from_attributes = True
127 changes: 127 additions & 0 deletions margin_app/app/tests/api/order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
Unit tests for Order API endpoints using function-based approach without async/await.
"""

import uuid
from unittest.mock import MagicMock, patch

import pytest
from fastapi import FastAPI, status
from fastapi.testclient import TestClient

from app.api.order import router
from app.main import app
from app.models.order import Order


@pytest.fixture
def app():
"""
Create a FastAPI app for testing.
"""
test_app = FastAPI()
test_app.include_router(router, prefix="/order")
return test_app


@pytest.fixture
def client(app):
"""
Create a test client for the app.
"""
return TestClient(app)


@pytest.fixture
def mock_add_new_order():
"""
Mock the add_new_order method of order_crud.
"""
with patch("app.api.order.order_crud.add_new_order") as mock:
yield mock


def create_mock_order():
"""Helper function to create a mock Order instance"""
order_id = uuid.uuid4()
user_id = uuid.uuid4()
position_id = uuid.uuid4()

mock_order = MagicMock(spec=Order)
mock_order.id = order_id
mock_order.user_id = user_id
mock_order.price = 100.50
mock_order.token = "BTC"
mock_order.position = position_id

return mock_order


def test_create_order_success(client, mock_add_new_order):
"""Test successful order creation"""
mock_order = create_mock_order()
mock_add_new_order.return_value = mock_order

response = client.post(
"/order/create_order",
json={
"user_id": str(mock_order.user_id),
"price": mock_order.price,
"token": mock_order.token,
"position": str(mock_order.position),
},
)

assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert "id" in data
assert data["price"] == mock_order.price
assert data["token"] == mock_order.token
assert data["user_id"] == str(mock_order.user_id)
assert data["position"] == str(mock_order.position)

mock_add_new_order.assert_called_once_with(
user_id=mock_order.user_id,
price=mock_order.price,
token=mock_order.token,
position=mock_order.position,
)


def test_create_order_invalid_data(client, mock_add_new_order):
"""Test order creation with invalid data"""
response = client.post(
"/order/create_order",
json={
"user_id": "not-a-uuid",
"price": 100.50,
"token": "BTC",
"position": str(uuid.uuid4()),
},
)

assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
data = response.json()
assert "detail" in data


def test_create_order_database_error(client, mock_add_new_order):
"""Test order creation with database error"""
mock_add_new_order.side_effect = Exception("Database error")
user_id = uuid.uuid4()
position_id = uuid.uuid4()

response = client.post(
"/order/create_order",
json={
"user_id": str(user_id),
"price": 100.50,
"token": "BTC",
"position": str(position_id),
},
)

assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
data = response.json()
assert "detail" in data
assert "Failed to create order" in data["detail"]

0 comments on commit 4e4d309

Please sign in to comment.