Updated API docs

This commit is contained in:
Donkie
2023-04-03 21:55:23 +02:00
parent 497540511f
commit 08cf68e937
5 changed files with 191 additions and 47 deletions

View File

@@ -29,29 +29,60 @@ class FilamentParameters(BaseModel):
"Filament name, to distinguish this filament type among others from the same vendor." "Filament name, to distinguish this filament type among others from the same vendor."
"Should contain its color for example." "Should contain its color for example."
), ),
example="PolyTerra™ Charcoal Black",
) )
vendor_id: Optional[int] = Field(description="The ID of the vendor of this filament type.") vendor_id: Optional[int] = Field(description="The ID of the vendor of this filament type.")
material: Optional[str] = Field(max_length=64, description="The material of this filament, e.g. PLA.") material: Optional[str] = Field(
price: Optional[float] = Field(ge=0, description="The price of this filament in the system configured currency.") max_length=64,
density: float = Field(gt=0, description="The density of this filament in g/cm3.") description="The material of this filament, e.g. PLA.",
diameter: float = Field(gt=0, description="The diameter of this filament in mm.") example="PLA",
weight: Optional[float] = Field(gt=0, description="The weight of the filament in a full spool.") )
spool_weight: Optional[float] = Field(gt=0, description="The empty spool weight.") price: Optional[float] = Field(
article_number: Optional[str] = Field(max_length=64, description="Vendor article number, e.g. EAN, QR code, etc.") ge=0,
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this filament type.") description="The price of this filament in the system configured currency.",
example=20.0,
)
density: float = Field(gt=0, description="The density of this filament in g/cm3.", example=1.24)
diameter: float = Field(gt=0, description="The diameter of this filament in mm.", example=1.75)
weight: Optional[float] = Field(
gt=0,
description="The weight of the filament in a full spool, in grams. (net weight)",
example=1000,
)
spool_weight: Optional[float] = Field(gt=0, description="The empty spool weight, in grams.", example=140)
article_number: Optional[str] = Field(
max_length=64,
description="Vendor article number, e.g. EAN, QR code, etc.",
example="PM70820",
)
comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this filament type.",
example="",
)
class FilamentUpdateParameters(FilamentParameters): class FilamentUpdateParameters(FilamentParameters):
density: Optional[float] = Field(gt=0, description="The density of this filament in g/cm3.") density: Optional[float] = Field(gt=0, description="The density of this filament in g/cm3.", example=1.24)
diameter: Optional[float] = Field(gt=0, description="The diameter of this filament in mm.") diameter: Optional[float] = Field(gt=0, description="The diameter of this filament in mm.", example=1.75)
@router.get("/") @router.get(
"/",
name="Find filaments",
description="Get a list of filaments that matches the search query.",
response_model_exclude_none=True,
)
async def find(_vendor: Union[int, None] = None) -> list[Filament]: async def find(_vendor: Union[int, None] = None) -> list[Filament]:
return [] return []
@router.get("/{filament_id}") @router.get(
"/{filament_id}",
name="Get filament",
description="Get a specific filament.",
response_model_exclude_none=True,
)
async def get( async def get(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
filament_id: int, filament_id: int,
@@ -60,7 +91,12 @@ async def get(
return Filament.from_db(db_item) return Filament.from_db(db_item)
@router.post("/") @router.post(
"/",
name="Add filament",
description="Add a new filament to the database.",
response_model_exclude_none=True,
)
async def create( async def create(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
body: FilamentParameters, body: FilamentParameters,
@@ -82,7 +118,12 @@ async def create(
return Filament.from_db(db_item) return Filament.from_db(db_item)
@router.patch("/{filament_id}") @router.patch(
"/{filament_id}",
name="Update filament",
description="Update any attribute of a filament. Only fields specified in the request will be affected.",
response_model_exclude_none=True,
)
async def update( async def update(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
filament_id: int, filament_id: int,
@@ -106,6 +147,8 @@ async def update(
@router.delete( @router.delete(
"/{filament_id}", "/{filament_id}",
name="Delete filament",
description="Delete a filament.",
response_model=Message, response_model=Message,
responses={ responses={
403: {"model": Message}, 403: {"model": Message},

View File

@@ -14,8 +14,8 @@ class Message(BaseModel):
class Vendor(BaseModel): class Vendor(BaseModel):
id: int = Field(description="Unique internal ID of this vendor.") id: int = Field(description="Unique internal ID of this vendor.")
name: str = Field(max_length=64, description="Vendor name.") name: str = Field(max_length=64, description="Vendor name.", example="Polymaker")
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this vendor.") comment: Optional[str] = Field(max_length=1024, description="Free text comment about this vendor.", example="")
@staticmethod @staticmethod
def from_db(item: models.Vendor) -> "Vendor": def from_db(item: models.Vendor) -> "Vendor":
@@ -35,16 +35,37 @@ class Filament(BaseModel):
"Filament name, to distinguish this filament type among others from the same vendor." "Filament name, to distinguish this filament type among others from the same vendor."
"Should contain its color for example." "Should contain its color for example."
), ),
example="PolyTerra™ Charcoal Black",
) )
vendor: Optional[Vendor] = Field(description="The vendor of this filament type.") vendor: Optional[Vendor] = Field(description="The vendor of this filament type.")
material: Optional[str] = Field(max_length=64, description="The material of this filament, e.g. PLA.") material: Optional[str] = Field(
price: Optional[float] = Field(ge=0, description="The price of this filament in the system configured currency.") max_length=64,
density: float = Field(gt=0, description="The density of this filament in g/cm3.") description="The material of this filament, e.g. PLA.",
diameter: float = Field(gt=0, description="The diameter of this filament in mm.") example="PLA",
weight: Optional[float] = Field(gt=0, description="The weight of the filament in a full spool.") )
spool_weight: Optional[float] = Field(gt=0, description="The empty spool weight.") price: Optional[float] = Field(
article_number: Optional[str] = Field(max_length=64, description="Vendor article number, e.g. EAN, QR code, etc.") ge=0,
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this filament type.") description="The price of this filament in the system configured currency.",
example=20.0,
)
density: float = Field(gt=0, description="The density of this filament in g/cm3.", example=1.24)
diameter: float = Field(gt=0, description="The diameter of this filament in mm.", example=1.75)
weight: Optional[float] = Field(
gt=0,
description="The weight of the filament in a full spool, in grams.",
example=1000,
)
spool_weight: Optional[float] = Field(gt=0, description="The empty spool weight, in grams.", example=140)
article_number: Optional[str] = Field(
max_length=64,
description="Vendor article number, e.g. EAN, QR code, etc.",
example="PM70820",
)
comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this filament type.",
example="",
)
@staticmethod @staticmethod
def from_db(item: models.Filament) -> "Filament": def from_db(item: models.Filament) -> "Filament":
@@ -70,10 +91,18 @@ class Spool(BaseModel):
first_used: Optional[datetime] = Field(description="First logged occurence of spool usage.") first_used: Optional[datetime] = Field(description="First logged occurence of spool usage.")
last_used: Optional[datetime] = Field(description="Last logged occurence of spool usage.") last_used: Optional[datetime] = Field(description="Last logged occurence of spool usage.")
filament: Filament = Field(description="The filament type of this spool.") filament: Filament = Field(description="The filament type of this spool.")
weight: float = Field(ge=0, description="Remaining weight of filament on the spool.") weight: float = Field(ge=0, description="Remaining weight of filament on the spool.", example=500)
location: Optional[str] = Field(max_length=64, description="Where this spool can be found.") location: Optional[str] = Field(max_length=64, description="Where this spool can be found.", example="Shelf A")
lot_nr: Optional[str] = Field(max_length=64, description="Vendor manufacturing lot/batch number of the spool.") lot_nr: Optional[str] = Field(
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this specific spool.") max_length=64,
description="Vendor manufacturing lot/batch number of the spool.",
example="52342",
)
comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this specific spool.",
example="",
)
@staticmethod @staticmethod
def from_db(item: models.Spool) -> "Spool": def from_db(item: models.Spool) -> "Spool":

View File

@@ -33,10 +33,19 @@ class SpoolParameters(BaseModel):
"Remaining weight of filament on the spool. " "Remaining weight of filament on the spool. "
"Leave empty to assume a full spool based on the weight parameters of the filament type." "Leave empty to assume a full spool based on the weight parameters of the filament type."
), ),
example=500,
)
location: Optional[str] = Field(max_length=64, description="Where this spool can be found.", example="Shelf A")
lot_nr: Optional[str] = Field(
max_length=64,
description="Vendor manufacturing lot/batch number of the spool.",
example="52342",
)
comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this specific spool.",
example="",
) )
location: Optional[str] = Field(max_length=64, description="Where this spool can be found.")
lot_nr: Optional[str] = Field(max_length=64, description="Vendor manufacturing lot/batch number of the spool.")
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this specific spool.")
class SpoolUpdateParameters(SpoolParameters): class SpoolUpdateParameters(SpoolParameters):
@@ -44,16 +53,26 @@ class SpoolUpdateParameters(SpoolParameters):
class SpoolUseParameters(BaseModel): class SpoolUseParameters(BaseModel):
use_length: Optional[float] = Field(description="Length of filament to reduce by, in mm.") use_length: Optional[float] = Field(description="Length of filament to reduce by, in mm.", example=2.2)
use_weight: Optional[float] = Field(description="Filament weight to reduce by, in g.") use_weight: Optional[float] = Field(description="Filament weight to reduce by, in g.", example=5.3)
@router.get("/") @router.get(
"/",
name="Find spool",
description="Get a list of spools that matches the search query.",
response_model_exclude_none=True,
)
async def find(_filament: Union[int, None] = None) -> list[Spool]: async def find(_filament: Union[int, None] = None) -> list[Spool]:
return [] return []
@router.get("/{spool_id}") @router.get(
"/{spool_id}",
name="Get spool",
description="Get a specific spool.",
response_model_exclude_none=True,
)
async def get( async def get(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
spool_id: int, spool_id: int,
@@ -64,6 +83,9 @@ async def get(
@router.post( @router.post(
"/", "/",
name="Add spool",
description="Add a new spool to the database.",
response_model_exclude_none=True,
response_model=Spool, response_model=Spool,
responses={ responses={
400: {"model": Message}, 400: {"model": Message},
@@ -92,7 +114,12 @@ async def create( # noqa: ANN201
) )
@router.patch("/{spool_id}") @router.patch(
"/{spool_id}",
name="Update spool",
description="Update any attribute of a spool. Only fields specified in the request will be affected.",
response_model_exclude_none=True,
)
async def update( async def update(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
spool_id: int, spool_id: int,
@@ -114,7 +141,11 @@ async def update(
return Spool.from_db(db_item) return Spool.from_db(db_item)
@router.delete("/{spool_id}") @router.delete(
"/{spool_id}",
name="Delete spool",
description="Delete a spool.",
)
async def delete( async def delete(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
spool_id: int, spool_id: int,
@@ -125,6 +156,13 @@ async def delete(
@router.put( @router.put(
"/{spool_id}/use", "/{spool_id}/use",
name="Use spool filament",
description=(
"Use some length or weight of filament from the spool."
" Specify either a length or a weight, not both."
" Will do nothing if the spool is empty (you have to keep track of that by yourself)."
),
response_model_exclude_none=True,
response_model=Spool, response_model=Spool,
responses={ responses={
400: {"model": Message}, 400: {"model": Message},

View File

@@ -21,21 +21,39 @@ router = APIRouter(
class VendorParameters(BaseModel): class VendorParameters(BaseModel):
name: str = Field(max_length=64, description="Vendor name.") name: str = Field(max_length=64, description="Vendor name.", example="Polymaker")
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this vendor.") comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this vendor.",
example="",
)
class VendorUpdateParameters(VendorParameters): class VendorUpdateParameters(VendorParameters):
name: Optional[str] = Field(max_length=64, description="Vendor name.") name: Optional[str] = Field(max_length=64, description="Vendor name.", example="Polymaker")
comment: Optional[str] = Field(max_length=1024, description="Free text comment about this vendor.") comment: Optional[str] = Field(
max_length=1024,
description="Free text comment about this vendor.",
example="",
)
@router.get("/") @router.get(
"/",
name="Find vendor",
description="Get a list of vendors that matches the search query.",
response_model_exclude_none=True,
)
async def find(_name: Union[int, None] = None) -> list[Vendor]: async def find(_name: Union[int, None] = None) -> list[Vendor]:
return [] return []
@router.get("/{vendor_id}") @router.get(
"/{vendor_id}",
name="Get vendor",
description="Get a specific vendor.",
response_model_exclude_none=True,
)
async def get( async def get(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
vendor_id: int, vendor_id: int,
@@ -44,7 +62,12 @@ async def get(
return Vendor.from_db(db_item) return Vendor.from_db(db_item)
@router.post("/") @router.post(
"/",
name="Add vendor",
description="Add a new vendor to the database.",
response_model_exclude_none=True,
)
async def create( async def create(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
body: VendorParameters, body: VendorParameters,
@@ -58,7 +81,12 @@ async def create(
return Vendor.from_db(db_item) return Vendor.from_db(db_item)
@router.patch("/{vendor_id}") @router.patch(
"/{vendor_id}",
name="Update vendor",
description="Update any attribute of a vendor. Only fields specified in the request will be affected.",
response_model_exclude_none=True,
)
async def update( async def update(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
vendor_id: int, vendor_id: int,
@@ -78,7 +106,13 @@ async def update(
return Vendor.from_db(db_item) return Vendor.from_db(db_item)
@router.delete("/{vendor_id}") @router.delete(
"/{vendor_id}",
name="Delete vendor",
description=(
"Delete a vendor. The vendor attribute of any filaments who refer to the deleted vendor will be cleared."
),
)
async def delete( async def delete(
db: Annotated[AsyncSession, Depends(get_db_session)], db: Annotated[AsyncSession, Depends(get_db_session)],
vendor_id: int, vendor_id: int,

View File

@@ -2,8 +2,8 @@
from typing import Optional from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from spoolman.database import models, vendor from spoolman.database import models, vendor
from spoolman.exceptions import ItemDeleteError, ItemNotFoundError from spoolman.exceptions import ItemDeleteError, ItemNotFoundError