Skip to content

Commit

Permalink
refactor into separate domain directories
Browse files Browse the repository at this point in the history
  • Loading branch information
patelnets committed May 2, 2024
1 parent aa0c7c7 commit 3d64b25
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 181 deletions.
108 changes: 3 additions & 105 deletions backend/src/api/index.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
from fastapi import FastAPI, HTTPException
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from mangum import Mangum

from api.lib import dynamo
from api.models import models
from api.services.product import ProductNotFoundError, ProductService
from api.services.product import delete_all_products as delete_all_products_service
from api.services.product import (
get_presigned_url_for_product,
get_product,
get_products,
)
from api.product.views import router

app = FastAPI()

Expand All @@ -36,100 +28,6 @@ def get_root():
return {"message": "Hello World"}


@app.get("/products", response_model=models.ProductsListResponse)
def list_products(next_token: str = None):
products = get_products(next_token=next_token)
return products


@app.post("/products", status_code=201, response_model=models.ProductResponse)
def post_product(payload: models.CreatePayload):
res = dynamo.create_product(
stores=payload.stores, name=payload.name, categories=payload.categories
)
return res


@app.get("/products/{product_id}", response_model=models.ProductResponse)
def get_product_route(product_id: str):
try:
return get_product(product_id)
except ProductNotFoundError as err:
raise HTTPException(status_code=404, detail="Product not found") from err
except Exception as err:
print(err)
raise HTTPException(status_code=500, detail="Something went wrong") from err


@app.patch("/products/{product_id}")
def update_product(product_id: str, payload: models.UpdatePayload):
try:
dynamo.update_product(
product_id=product_id,
stores=payload.stores,
name=payload.name,
categories=payload.categories,
)
except ProductNotFoundError as err:
raise HTTPException(status_code=404, detail="Product not found") from err


@app.delete("/products/{product_id}", status_code=200)
def delete_product(product_id: str):
try:
ProductService.delete_by_id(product_id=product_id)

except ProductNotFoundError as err:
raise HTTPException(status_code=404, detail="Product not found") from err


@app.get("/products/{product_id}/image-upload-pre-signed-url")
def upload_pre_signed(product_id: str):
try:
url = get_presigned_url_for_product(product_id)

except Exception as err:
raise HTTPException(status_code=500, detail="Something went wrong") from err

return {"url": url}


@app.delete("/products/all/force", status_code=200)
def delete_all_products():
delete_all_products_service()


@app.post("/products/bulk", status_code=201)
def bulk_upload(payload: models.ProductsBulkUploadRequest):
try:
for product in payload.products:
try:
existing_products = dynamo.get_products_by_name(product.name)
if len(existing_products) > 1:
raise HTTPException(
status_code=500,
detail="There are more than one products with the same name",
)
if len(existing_products) == 0:
raise ProductNotFoundError
dynamo.update_product(
product_id=existing_products[0]["id"],
stores=product.stores,
name=product.name,
categories=product.categories,
)
except ProductNotFoundError:
dynamo.create_product(
stores=product.stores,
name=product.name,
categories=product.categories,
)

except Exception as err:
print(err)
raise HTTPException(status_code=500, detail="Something went wrong") from err

return {"message": f"Successfully added {len(payload.products)} products"}

app.include_router(router)

handler = Mangum(app)
2 changes: 1 addition & 1 deletion backend/src/api/lib/dynamo.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import boto3
from boto3.dynamodb.conditions import Attr, Key

from api.services.product import ProductNotFoundError
from api.product.exceptions import ProductNotFoundError

table = boto3.resource("dynamodb").Table(os.environ["table"])

Expand Down
31 changes: 0 additions & 31 deletions backend/src/api/models/models.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
from typing import Optional

from pydantic import BaseModel


class ProductResponse(BaseModel):
id: str
name: str
stores: list[str]
images: list[str]
image_urls: dict[str, str] = {}
categories: list[str]
header_image: str = None


class CreatePayload(BaseModel):
name: str
stores: list[str]
categories: list[str]


class UpdatePayload(BaseModel):
name: Optional[str]
stores: Optional[list[str]]
categories: Optional[list[str]]


class ProductsListResponse(BaseModel):
products: list[ProductResponse]
next_token: str = None


class ProductsBulkUploadRequest(BaseModel):
products: list[CreatePayload]
2 changes: 2 additions & 0 deletions backend/src/api/product/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ProductNotFoundError(Exception):
pass
34 changes: 34 additions & 0 deletions backend/src/api/product/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Optional

from pydantic import BaseModel


class ProductResponse(BaseModel):
id: str
name: str
stores: list[str]
images: list[str]
image_urls: dict[str, str] = {}
categories: list[str]
header_image: str = None


class ProductsListResponse(BaseModel):
products: list[ProductResponse]
next_token: str = None


class CreatePayload(BaseModel):
name: str
stores: list[str]
categories: list[str]


class UpdatePayload(BaseModel):
name: Optional[str]
stores: Optional[list[str]]
categories: Optional[list[str]]


class ProductsBulkUploadRequest(BaseModel):
products: list[CreatePayload]
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,31 @@
s3 = boto3.client("s3")


class ProductNotFoundError(Exception):
pass
def get_product(product_id):
product = dynamo.get_product(product_id)
images = get_all_images_for_product(product_id)
if "categories" not in product:
product["categories"] = []
for image_id in images:
if "image_urls" not in product:
product["image_urls"] = {}
product["image_urls"][
image_id
] = f"https://froodom-frontend.s3.eu-west-2.amazonaws.com/{image_id}"

if len(images) > 0:
product["header_image"] = (
f"https://froodom-frontend.s3.eu-west-2.amazonaws.com/{images[0]}"
)

return product

def get_all_images_for_product(product_id):
res = s3.list_objects_v2(
Bucket=os.environ["bucket"], Prefix=f"images/{product_id}/"
)
if "Contents" in res:
return [obj["Key"] for obj in res["Contents"]]
return []

def delete_by_id(product_id: str):
product = get_product(product_id)
for image_id in product["images"]:
delete_object(bucket="froodom-frontend", key=image_id)
dynamo.delete_product(product_id)


def get_products(next_token=None):
Expand All @@ -42,24 +56,23 @@ def get_products(next_token=None):
return res


def get_product(product_id):
product = dynamo.get_product(product_id)
images = get_all_images_for_product(product_id)
if "categories" not in product:
product["categories"] = []
for image_id in images:
if "image_urls" not in product:
product["image_urls"] = {}
product["image_urls"][
image_id
] = f"https://froodom-frontend.s3.eu-west-2.amazonaws.com/{image_id}"
def delete_all_products():
res = dynamo.list_products()
for product in res["products"]:
images = get_all_images_for_product(product["id"])
for image_id in images:
s3.delete_object(Bucket="froodom-frontend", Key=image_id)
dynamo.delete_product(product["id"])
return res

if len(images) > 0:
product["header_image"] = (
f"https://froodom-frontend.s3.eu-west-2.amazonaws.com/{images[0]}"
)

return product
def get_all_images_for_product(product_id):
res = s3.list_objects_v2(
Bucket=os.environ["bucket"], Prefix=f"images/{product_id}/"
)
if "Contents" in res:
return [obj["Key"] for obj in res["Contents"]]
return []


def get_presigned_url_for_product(product_id: str):
Expand All @@ -70,22 +83,3 @@ def get_presigned_url_for_product(product_id: str):
Params={"Bucket": "froodom-frontend", "Key": f"images/{product_id}/{uuid}"},
)
return url


def delete_all_products():
res = dynamo.list_products()
for product in res["products"]:
images = get_all_images_for_product(product["id"])
for image_id in images:
s3.delete_object(Bucket="froodom-frontend", Key=image_id)
dynamo.delete_product(product["id"])
return res


class ProductService:
@staticmethod
def delete_by_id(product_id: str):
product = get_product(product_id)
for image_id in product["images"]:
delete_object(bucket="froodom-frontend", key=image_id)
dynamo.delete_product(product_id)
Loading

0 comments on commit 3d64b25

Please sign in to comment.