import os import sqlite3 from typing import Annotated, Optional from fastapi import Depends, FastAPI from fastapi.responses import JSONResponse from pydantic import BaseModel, Field, condecimal, conint, constr, root_validator import app.database as database from app.order_processor import FailedToProcessOrderError, process_order from app.types import Order, OrderSide, OrderType app = FastAPI() class CreateOrderModel(BaseModel): type_: OrderType = Field(..., alias="type") side: OrderSide instrument: constr(min_length=12, max_length=12) limit_price: Optional[condecimal(decimal_places=2)] quantity: conint(gt=0) @root_validator def validator(cls, values: dict): if values.get("type_") == "market" and values.get("limit_price"): raise ValueError( "Providing a `limit_price` is prohibited for type `market`" ) if values.get("type_") == "limit" and not values.get("limit_price"): raise ValueError("Attribute `limit_price` is required for type `limit`") return values class CreateOrderResponseModel(Order): pass async def get_db(): # Replace with proper db connection pooling implementation db = database.connect(os.getenv("DB_CONNECTION")) database.apply_database_schema(db) try: yield db finally: db.close() @app.post("/orders", status_code=201) async def create_order( model: CreateOrderModel, db: Annotated[sqlite3.Connection, Depends(get_db)] ): try: order = process_order(db, model) return CreateOrderResponseModel( id=order.id_, created_at=order.created_at, type=order.type_, side=order.side, instrument=order.instrument, limit_price=order.limit_price, quantity=order.quantity, ) except FailedToProcessOrderError: return JSONResponse( content={"message": "Internal server error while placing the order"}, status_code=500, )