add validation

rest-api
Cizz22 1 month ago
parent bbfa010b39
commit 7cad6cc8c4

@ -1,14 +1,15 @@
from typing import Optional from typing import Annotated, Optional
from fastapi import APIRouter, HTTPException, status, Query from fastapi import APIRouter, Depends, HTTPException, status, Query
from pydantic import ValidationError
from src.acquisition_cost.model import AcquisitionData from src.acquisition_cost.model import AcquisitionData
from src.acquisition_cost.schema import AcquisitionCostDataPagination, AcquisitionCostDataRead, AcquisitionCostDataCreate, AcquisitionCostDataUpdate from src.acquisition_cost.schema import AcquisitionCostDataPagination, AcquisitionCostDataRead, AcquisitionCostDataCreate, AcquisitionCostDataUpdate, ListQueryParams
from src.acquisition_cost.service import get, get_all, create, update, delete from src.acquisition_cost.service import get, get_all, create, update, delete
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession from src.database.core import DbSession
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
from src.models import StandardResponse from src.models import CommonParams, StandardResponse
router = APIRouter() router = APIRouter()
@ -17,14 +18,13 @@ router = APIRouter()
async def get_yeardatas( async def get_yeardatas(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
items_per_page: Optional[int] = Query(5), params: Annotated[ListQueryParams, Query()],
search: Optional[str] = Query(None),
): ):
"""Get all acquisition_cost_data pagination.""" """Get all acquisition_cost_data pagination."""
get_acquisition_cost_data = await get_all( get_acquisition_cost_data = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
search=search, search=params.search,
common=common, common=common,
) )
# return # return

@ -3,7 +3,7 @@ from typing import List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import Field
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
class AcquisitionCostDataBase(DefaultBase): class AcquisitionCostDataBase(DefaultBase):
@ -31,3 +31,16 @@ class AcquisitionCostDataRead(AcquisitionCostDataBase):
class AcquisitionCostDataPagination(Pagination): class AcquisitionCostDataPagination(Pagination):
items: List[AcquisitionCostDataRead] = [] items: List[AcquisitionCostDataRead] = []
class ListQueryParams(CommonParams):
items_per_page: Optional[int] = Field(
default=5,
ge=1,
le=1000,
description="Number of items per page"
)
search: Optional[str] = Field(
default=None,
description="Search keyword"
)

@ -1,4 +1,4 @@
from typing import List, Optional from typing import Annotated, List, Optional
from fastapi import APIRouter, HTTPException, status, Query from fastapi import APIRouter, HTTPException, status, Query
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
import json import json
@ -13,6 +13,7 @@ from src.equipment.schema import (
EquipmentTop10Pagination, EquipmentTop10Pagination,
EquipmentUpdate, EquipmentUpdate,
CountRemainingLifeResponse, CountRemainingLifeResponse,
ListQueryParams,
) )
from src.equipment.service import ( from src.equipment.service import (
get_master_by_assetnum, get_master_by_assetnum,
@ -34,7 +35,7 @@ from src.modules.equipment.Eac import Eac
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
from src.database.core import DbSession, CollectorDbSession from src.database.core import DbSession, CollectorDbSession
from src.auth.service import CurrentUser, Token from src.auth.service import CurrentUser, Token
from src.models import StandardResponse from src.models import CommonParams, StandardResponse
router = APIRouter() router = APIRouter()
@ -43,15 +44,14 @@ router = APIRouter()
async def get_equipments( async def get_equipments(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
items_per_page: Optional[int] = Query(5), params: Annotated[ListQueryParams, Query()],
search: Optional[str] = Query(None),
): ):
"""Get all equipment pagination.""" """Get all equipment pagination."""
# return # return
equipment_data = await get_all( equipment_data = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
search=search, search=params.search,
common=common, common=common,
) )
return StandardResponse( return StandardResponse(
@ -119,7 +119,7 @@ async def simulate_equipment(db_session: DbSession, assetnum: str):
"/count-remaining-life", "/count-remaining-life",
response_model=StandardResponse[CountRemainingLifeResponse], response_model=StandardResponse[CountRemainingLifeResponse],
) )
async def get_count_remaining_life_equipment(db_session: DbSession, common: CommonParameters): async def get_count_remaining_life_equipment(db_session: DbSession, common: CommonParameters, params: Annotated[CommonParams, Query()]):
count = await get_count_remaining_life(db_session=db_session, common=common) count = await get_count_remaining_life(db_session=db_session, common=common)
return StandardResponse( return StandardResponse(
data=count, data=count,
@ -130,7 +130,7 @@ async def get_count_remaining_life_equipment(db_session: DbSession, common: Comm
"/top-10-replacement-priorities", "/top-10-replacement-priorities",
response_model=StandardResponse[EquipmentTop10Pagination], response_model=StandardResponse[EquipmentTop10Pagination],
) )
async def get_calculated_top_10_replacement_priorities(db_session: DbSession, common: CommonParameters): async def get_calculated_top_10_replacement_priorities(db_session: DbSession, common: CommonParameters, params: Annotated[CommonParams, Query()]):
equipment_data = await get_top_10_replacement_priorities(db_session=db_session, common=common) equipment_data = await get_top_10_replacement_priorities(db_session=db_session, common=common)
return StandardResponse( return StandardResponse(
data=equipment_data, data=equipment_data,
@ -141,7 +141,7 @@ async def get_calculated_top_10_replacement_priorities(db_session: DbSession, co
"/top-10-economic-life", "/top-10-economic-life",
response_model=StandardResponse[EquipmentTop10Pagination], response_model=StandardResponse[EquipmentTop10Pagination],
) )
async def get_calculated_top_10_economic_life(db_session: DbSession, common: CommonParameters): async def get_calculated_top_10_economic_life(db_session: DbSession, common: CommonParameters, params: Annotated[CommonParams, Query()]):
equipment_data = await get_top_10_economic_life(db_session=db_session, common=common) equipment_data = await get_top_10_economic_life(db_session=db_session, common=common)
return StandardResponse( return StandardResponse(
data=equipment_data, data=equipment_data,

@ -3,7 +3,7 @@ from typing import List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import Field
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
MAX_PRICE = 1_000_000_000_000_000 # thousands of trillion MAX_PRICE = 1_000_000_000_000_000 # thousands of trillion
@ -150,3 +150,16 @@ class CountRemainingLifeResponse(DefaultBase):
safe: int safe: int
warning: int warning: int
critical: int critical: int
class ListQueryParams(CommonParams):
items_per_page: Optional[int] = Field(
default=5,
ge=1,
le=1000,
description="Number of items per page"
)
search: Optional[str] = Field(
default=None,
description="Search keyword"
)

@ -3,7 +3,7 @@ from typing import Annotated, List, Optional
from src.models import StandardResponse from src.models import StandardResponse
from .service import get_all_master, get_master from .service import get_all_master, get_master
from fastapi import APIRouter, HTTPException, Query, status from fastapi import APIRouter, HTTPException, Query, status
from .schema import EquipmentMasterPaginated, EquipmentMasterRead from .schema import EquipmentMasterPaginated, EquipmentMasterQuery, EquipmentMasterRead
from src.database.service import search_filter_sort_paginate, CommonParameters from src.database.service import search_filter_sort_paginate, CommonParameters
from src.database.core import DbSession from src.database.core import DbSession
@ -14,14 +14,12 @@ router = APIRouter()
async def get_all_equipment_master_tree( async def get_all_equipment_master_tree(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
parent_id: Annotated[Optional[str], Query(description="Parent ID")] = None, params: Annotated[EquipmentMasterQuery, Query()],
search: Optional[str] = Query(None),
items_per_page: Optional[int] = Query(5),
): ):
equipment_masters = await get_all_master( equipment_masters = await get_all_master(
parent_id=parent_id, parent_id=params.parent_id,
search=search, search=params.search,
items_per_page=items_per_page, items_per_page=params.items_per_page,
db_session=db_session, db_session=db_session,
common=common, common=common,
) )

@ -3,7 +3,7 @@ from typing import ForwardRef, List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import Field
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
class EquipmentMasterBase(DefaultBase): class EquipmentMasterBase(DefaultBase):
@ -42,3 +42,9 @@ class EquipmentMasterRead(EquipmentMasterBase):
class EquipmentMasterPaginated(Pagination): class EquipmentMasterPaginated(Pagination):
items: List[EquipmentMasterRead] = [] items: List[EquipmentMasterRead] = []
class EquipmentMasterQuery(CommonParams):
parent_id : Optional[str] = None
items_per_page : Optional[int] = 5
search : Optional[str] = None

@ -1,8 +1,8 @@
from typing import Optional from typing import Annotated, Optional
from fastapi import APIRouter, HTTPException, status, Query from fastapi import APIRouter, HTTPException, status, Query
from src.manpower_cost.model import ManpowerCost from src.manpower_cost.model import ManpowerCost
from src.manpower_cost.schema import ManpowerCostPagination, ManpowerCostRead, ManpowerCostCreate, ManpowerCostUpdate from src.manpower_cost.schema import ManpowerCostPagination, ManpowerCostRead, ManpowerCostCreate, ManpowerCostUpdate, QueryParams
from src.manpower_cost.service import get, get_all, create, update, delete from src.manpower_cost.service import get, get_all, create, update, delete
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
@ -17,14 +17,13 @@ router = APIRouter()
async def get_yeardatas( async def get_yeardatas(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
items_per_page: Optional[int] = Query(5), params: Annotated[QueryParams, Query()],
search: Optional[str] = Query(None),
): ):
"""Get all acquisition_cost_data pagination.""" """Get all acquisition_cost_data pagination."""
get_acquisition_cost_data = await get_all( get_acquisition_cost_data = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
search=search, search=params.search,
common=common, common=common,
) )
# return # return

@ -3,7 +3,7 @@ from typing import List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import Field
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
class ManpowerCostBase(DefaultBase): class ManpowerCostBase(DefaultBase):
@ -31,3 +31,8 @@ class ManpowerCostRead(ManpowerCostBase):
class ManpowerCostPagination(Pagination): class ManpowerCostPagination(Pagination):
items: List[ManpowerCostRead] = [] items: List[ManpowerCostRead] = []
class QueryParams(CommonParams):
items_per_page: Optional[int] = Field(5)
search: Optional[str] = Field(None)

@ -1,8 +1,8 @@
from typing import Optional from typing import Annotated, Optional
from fastapi import APIRouter, HTTPException, status, Query from fastapi import APIRouter, HTTPException, status, Query
from src.manpower_cost.model import ManpowerCost from src.manpower_cost.model import ManpowerCost
from src.manpower_cost.schema import ManpowerCostPagination, ManpowerCostRead, ManpowerCostCreate, ManpowerCostUpdate from src.manpower_cost.schema import ManpowerCostPagination, ManpowerCostRead, ManpowerCostCreate, ManpowerCostUpdate, QueryParams
from src.manpower_cost.service import get, get_all, create, update, delete from src.manpower_cost.service import get, get_all, create, update, delete
from src.database.service import CommonParameters, search_filter_sort_paginate from src.database.service import CommonParameters, search_filter_sort_paginate
@ -17,14 +17,13 @@ router = APIRouter()
async def get_yeardatas( async def get_yeardatas(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
items_per_page: Optional[int] = Query(5), params: Annotated[QueryParams, Query()],
search: Optional[str] = Query(None),
): ):
"""Get all acquisition_cost_data pagination.""" """Get all acquisition_cost_data pagination."""
get_acquisition_cost_data = await get_all( get_acquisition_cost_data = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
search=search, search=params.search,
common=common, common=common,
) )
# return # return

@ -3,7 +3,7 @@ from typing import List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import Field
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
class ManpowerCostBase(DefaultBase): class ManpowerCostBase(DefaultBase):
@ -31,3 +31,7 @@ class ManpowerCostRead(ManpowerCostBase):
class ManpowerCostPagination(Pagination): class ManpowerCostPagination(Pagination):
items: List[ManpowerCostRead] = [] items: List[ManpowerCostRead] = []
class QueryParams(CommonParams):
items_per_page: Optional[int] = Field(5)
search: Optional[str] = Field(None)

@ -1,7 +1,9 @@
from typing import Optional, List from typing import Annotated, Optional, List
from fastapi import APIRouter, HTTPException, status, Query from fastapi import APIRouter, HTTPException, status, Query
from sqlalchemy import Select from sqlalchemy import Select
from src.manpower_cost.schema import QueryParams
from .model import MasterData from .model import MasterData
from .schema import ( from .schema import (
MasterDataPagination, MasterDataPagination,
@ -23,15 +25,14 @@ router = APIRouter()
async def get_masterdatas( async def get_masterdatas(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
items_per_page: Optional[int] = Query(5), params: Annotated[QueryParams, Query()],
search: Optional[str] = Query(None),
): ):
"""Get all documents.""" """Get all documents."""
# return # return
master_datas = await get_all( master_datas = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
search=search, search=params.search,
common=common, common=common,
) )
return StandardResponse( return StandardResponse(

@ -2,7 +2,7 @@ from datetime import datetime
from typing import List, Optional from typing import List, Optional
from uuid import UUID from uuid import UUID
from pydantic import Field from pydantic import BaseModel, Field
from src.models import DefaultBase, Pagination from src.models import DefaultBase, Pagination
from src.auth.service import CurrentUser from src.auth.service import CurrentUser
@ -50,3 +50,15 @@ class MasterDataRead(MasterdataBase):
class MasterDataPagination(Pagination): class MasterDataPagination(Pagination):
items: List[MasterDataRead] = [] items: List[MasterDataRead] = []
class QueryParams(BaseModel):
items_per_page: Optional[int] = Field(
5,
ge=1,
description="Items per page"
)
search: Optional[str] = Field(
None,
description="Search keyword"
)

@ -1,4 +1,4 @@
from typing import List, Optional from typing import Annotated, List, Optional
from uuid import UUID from uuid import UUID
from fastapi import APIRouter, HTTPException, Query, status from fastapi import APIRouter, HTTPException, Query, status
@ -12,6 +12,7 @@ from src.masterdata_simulations.schema import (
MasterDataSimulationPagination, MasterDataSimulationPagination,
MasterDataSimulationRead, MasterDataSimulationRead,
MasterDataSimulationUpdate, MasterDataSimulationUpdate,
QueryParams,
) )
from src.masterdata_simulations.service import ( from src.masterdata_simulations.service import (
bulk_update, bulk_update,
@ -30,15 +31,13 @@ router = APIRouter()
async def get_masterdata_simulations( async def get_masterdata_simulations(
db_session: DbSession, db_session: DbSession,
common: CommonParameters, common: CommonParameters,
simulation_id: UUID = Query(..., description="Simulation identifier"), params: Annotated[QueryParams, Query()],
items_per_page: Optional[int] = Query(5),
search: Optional[str] = Query(None),
): ):
master_datas = await get_all( master_datas = await get_all(
db_session=db_session, db_session=db_session,
items_per_page=items_per_page, items_per_page=params.items_per_page,
simulation_id=simulation_id, simulation_id=params.simulation_id,
search=search, search=params.search,
common=common, common=common,
) )
return StandardResponse(data=master_datas, message="Data retrieved successfully") return StandardResponse(data=master_datas, message="Data retrieved successfully")

@ -4,7 +4,7 @@ from uuid import UUID
from pydantic import Field from pydantic import Field
from src.masterdata.schema import MasterdataBase from src.masterdata.schema import MasterdataBase
from src.models import DefaultBase, Pagination from src.models import CommonParams, DefaultBase, Pagination
class MasterDataSimulationBase(MasterdataBase): class MasterDataSimulationBase(MasterdataBase):
@ -38,3 +38,16 @@ class MasterDataSimulationRead(MasterDataSimulationBase):
class MasterDataSimulationPagination(Pagination): class MasterDataSimulationPagination(Pagination):
items: List[MasterDataSimulationRead] = [] items: List[MasterDataSimulationRead] = []
class QueryParams(CommonParams):
simulation_id: UUID = Field(
...,
description="Simulation identifier",
)
items_per_page: Optional[int] = Field(
5,
ge=1,
description="Items per page"
)
search: Optional[str] = Field(None)

@ -1,6 +1,6 @@
# src/common/models.py # src/common/models.py
from datetime import datetime from datetime import datetime
from typing import Generic, Optional, TypeVar from typing import Generic, List, Optional, TypeVar
import uuid import uuid
from pydantic import BaseModel, Field, SecretStr from pydantic import BaseModel, Field, SecretStr
from sqlalchemy import Column, DateTime, String, func, event from sqlalchemy import Column, DateTime, String, func, event
@ -72,6 +72,8 @@ class DefaultBase(BaseModel):
validate_assignment = True validate_assignment = True
arbitrary_types_allowed = True arbitrary_types_allowed = True
str_strip_whitespace = True str_strip_whitespace = True
extra = "forbid"
populate_by_name=True
json_encoders = { json_encoders = {
# custom output conversion for datetime # custom output conversion for datetime
@ -99,3 +101,21 @@ class StandardResponse(BaseModel, Generic[T]):
data: Optional[T] = None data: Optional[T] = None
message: str = "Success" message: str = "Success"
status: ResponseStatus = ResponseStatus.SUCCESS status: ResponseStatus = ResponseStatus.SUCCESS
class CommonParams(DefaultBase):
# This ensures no extra query params are allowed
current_user: Optional[str] = Field(None, alias="currentUser")
page: int = Field(1, gt=0, lt=2147483647)
items_per_page: int = Field(5, gt=-2, lt=2147483647)
query_str: Optional[str] = Field(None, alias="q")
filter_spec: Optional[str] = Field(None, alias="filter")
sort_by: List[str] = Field(default_factory=list, alias="sortBy[]")
descending: List[bool] = Field(default_factory=list, alias="descending[]")
exclude: List[str] = Field(default_factory=list, alias="exclude[]")
all_params: int = Field(0, alias="all")
# Property to mirror your original return dict's bool conversion
@property
def is_all(self) -> bool:
return bool(self.all_params)
Loading…
Cancel
Save