70 lines
2.0 KiB
Python

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,
)