Skip to content

Commit

Permalink
Merge pull request #5 from Maua-Dev/add-repo
Browse files Browse the repository at this point in the history
Add repo to the template
  • Loading branch information
VgsStudio committed Aug 4, 2023
2 parents f303891 + 121ce25 commit 4f412d0
Show file tree
Hide file tree
Showing 9 changed files with 350 additions and 78 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ After that you need to clone your new repo, create a virtual environment and ins

uvicorn src.app.main:app

#### If you want to access the FAST API interface to interact with the API, you can access the following URL:

http://localhost:8000/docs

### Atention 🚨
In order to deploy your microservice in AWS Lambda, you need to follow some rules:
- The routes must be created using FastAPI decorators;
Expand Down
27 changes: 22 additions & 5 deletions src/app/entities/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(self, name: str=None, price: float=None, item_type: ItemTypeEnum=No
self.admin_permission = admin_permission

@staticmethod
def validate_name(name: str) -> Tuple[float, str]:
def validate_name(name: str) -> Tuple[bool, str]:
if name is None:
return (False, "Name is required")
if type(name) != str:
Expand All @@ -41,7 +41,7 @@ def validate_name(name: str) -> Tuple[float, str]:
return (True, "")

@staticmethod
def validate_price(price: float) -> Tuple[float, str]:
def validate_price(price: float) -> Tuple[bool, str]:
if price is None:
return (False, "Price is required")
if type(price) != float:
Expand All @@ -51,21 +51,35 @@ def validate_price(price: float) -> Tuple[float, str]:
return (True, "")

@staticmethod
def validate_item_type(item_type: ItemTypeEnum) -> Tuple[float, str]:
def validate_item_type(item_type: ItemTypeEnum) -> Tuple[bool, str]:
if item_type is None:
return (False, "Item type is required")
if type(item_type) != ItemTypeEnum:
return (False, "Item type must be a ItemTypeEnum")
return (True, "")

@staticmethod
def validate_admin_permission(admin_permission: bool) -> Tuple[float, str]:
def validate_admin_permission(admin_permission: bool) -> Tuple[bool, str]:
if admin_permission is None:
return (False, "Admin permission is required")
if type(admin_permission) != bool:
return (False, "Admin permission must be a boolean")
return (True, "")

@staticmethod
def validate_item_id(item_id: int) -> Tuple[bool, str]:
if item_id is None:
return (False, "Missing 'item_id' parameter")

if type(item_id) != int:
return (False, "Parameter 'item_id' must be an integer")

if item_id < 0:
return (False, "Parameter 'item_id' must be a positive integer")

return (True, "")


def to_dict(self):
return {
"name": self.name,
Expand All @@ -75,4 +89,7 @@ def to_dict(self):
}

def __eq__(self,other):
return self.name == other.name and self.price == other.price and self.item_type == other.item_type and self.admin_permission == other.admin_permission
return self.name == other.name and self.price == other.price and self.item_type == other.item_type and self.admin_permission == other.admin_permission

def __repr__(self):
return f"Item(name={self.name}, price={self.price}, item_type={self.item_type}, admin_permission={self.admin_permission})"
59 changes: 59 additions & 0 deletions src/app/environments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

from enum import Enum
import os

from .errors.environment_errors import EnvironmentNotFound

from .repo.item_repository_interface import IItemRepository


class STAGE(Enum):
DOTENV = "DOTENV"
DEV = "DEV"
PROD = "PROD"
TEST = "TEST"


class Environments:
"""
Defines the environment variables for the application. You should not instantiate this class directly. Please use Environments.get_envs() method instead.
Usage:
"""
stage: STAGE

def _configure_local(self):
from dotenv import load_dotenv
load_dotenv()
os.environ["STAGE"] = os.environ.get("STAGE") or STAGE.TEST.value

def load_envs(self):
if "STAGE" not in os.environ or os.environ["STAGE"] == STAGE.DOTENV.value:
self._configure_local()

self.stage = STAGE[os.environ.get("STAGE")]

@staticmethod
def get_item_repo() -> IItemRepository:
if Environments.get_envs().stage == STAGE.TEST:
from .repo.item_repository_mock import ItemRepositoryMock
return ItemRepositoryMock
# use "elif" conditional to add other stages
else:
raise EnvironmentNotFound("STAGE")


@staticmethod
def get_envs() -> "Environments":
"""
Returns the Environments object. This method should be used to get the Environments object instead of instantiating it directly.
:return: Environments (stage={self.stage})
"""
envs = Environments()
envs.load_envs()
return envs

def __repr__(self):
return self.__dict__
6 changes: 6 additions & 0 deletions src/app/errors/environment_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .base_error import BaseError


class EnvironmentNotFound(BaseError):
def __init__(self, env: str):
super().__init__(f'The environment {env} is wrong')
100 changes: 44 additions & 56 deletions src/app/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from fastapi import FastAPI, HTTPException
from mangum import Mangum

from .environments import Environments

from .repo.item_repository_mock import ItemRepositoryMock

from .errors.entity_errors import ParamNotValidated

from .enums.item_type_enum import ItemTypeEnum
Expand All @@ -10,30 +14,22 @@

app = FastAPI()

items = {
1: Item(name="Barbie", price=48.90, item_type=ItemTypeEnum.TOY, admin_permission=False),
2: Item(name="Hamburguer", price=38.00, item_type=ItemTypeEnum.FOOD, admin_permission=False),
3: Item(name="T-shirt", price=22.95, item_type=ItemTypeEnum.CLOTHES, admin_permission=False),
4: Item(name="Super Mario Bros", price=55.00, item_type=ItemTypeEnum.GAMES, admin_permission=True)
}

# TODO: Implement my logic here to handle the requests
repo = Environments.get_item_repo()()

@app.get("/items/get_all_items")
def get_all_items():
global items
return items
items = repo.get_all_items()
return {
"items": [item.to_dict() for item in items]
}

@app.get("/items/{item_id}")
def get_item(item_id: int):
if item_id is None:
raise HTTPException(status_code=400, detail="Missing 'item_id' parameter")

if type(item_id) != int:
raise HTTPException(status_code=400, detail="Parameter 'item_id' must be an integer")
validation_item_id = Item.validate_item_id(item_id=item_id)
if not validation_item_id[0]:
raise HTTPException(status_code=400, detail=validation_item_id[1])

global items
item = items.get(item_id)
item = repo.get_item(item_id)

if item is None:
raise HTTPException(status_code=404, detail="Item Not found")
Expand All @@ -46,14 +42,14 @@ def get_item(item_id: int):
@app.post("/items/create_item", status_code=201)
def create_item(request: dict):
item_id = request.get("item_id")
if item_id is None:
raise HTTPException(status_code=400, detail="Missing 'item_id' parameter")

if type(item_id) != int:
raise HTTPException(status_code=400, detail="Parameter 'item_id' must be an integer")

if item_id < 0:
raise HTTPException(status_code=400, detail="Parameter 'item_id' must be a positive integer")
validation_item_id = Item.validate_item_id(item_id=item_id)
if not validation_item_id[0]:
raise HTTPException(status_code=400, detail=validation_item_id[1])

item = repo.get_item(item_id)
if item is not None:
raise HTTPException(status_code=409, detail="Item already exists")

name = request.get("name")
price = request.get("price")
Expand All @@ -72,48 +68,44 @@ def create_item(request: dict):
except ParamNotValidated as err:
raise HTTPException(status_code=400, detail=err.message)

items[item_id] = item
item_response = repo.create_item(item, item_id)
return {
"item_id": item_id,
"item": item.to_dict()
"item": item_response.to_dict()
}

@app.delete("/items/delete_item")
def delete_item(request: dict):
item_id = request.get("item_id")
if item_id is None:
raise HTTPException(status_code=400, detail="Missing 'item_id' parameter")

if type(item_id) != int:
raise HTTPException(status_code=400, detail="Parameter 'item_id' must be an integer")

global items
item = items.get(item_id)
validation_item_id = Item.validate_item_id(item_id=item_id)
if not validation_item_id[0]:
raise HTTPException(status_code=400, detail=validation_item_id[1])

item = repo.get_item(item_id)

if item is None:
raise HTTPException(status_code=404, detail="Item Not found")

if item.admin_permission == True:
raise HTTPException(status_code=403, detail="Item Not found")

items.pop(item_id)
item_deleted = repo.delete_item(item_id)

return {
"item_id": item_id,
"item": item.to_dict()
"item": item_deleted.to_dict()
}

@app.put("/items/update_item")
def update_item(request: dict):
item_id = request.get("item_id")
if item_id is None:
raise HTTPException(status_code=400, detail="Missing 'item_id' parameter")

if type(item_id) != int:
raise HTTPException(status_code=400, detail="Parameter 'item_id' must be an integer")

global items
item = items.get(item_id)
validation_item_id = Item.validate_item_id(item_id=item_id)
if not validation_item_id[0]:
raise HTTPException(status_code=400, detail=validation_item_id[1])

item = repo.get_item(item_id)

if item is None:
raise HTTPException(status_code=404, detail="Item Not found")
Expand All @@ -123,27 +115,23 @@ def update_item(request: dict):

name = request.get("name")
price = request.get("price")
item_type = request.get("item_type")
admin_permission = request.get("admin_permission")

if name == None and price == None and item_type == None and admin_permission == None:
raise HTTPException(status_code=400, detail="Missing parameters")
if name != None:
items[item_id].name = name
if price != None:
items[item_id].price = price
if item_type != None:
if type(item_type) != str:
item_type_value = request.get("item_type")
if item_type_value != None:
if type(item_type_value) != str:
raise HTTPException(status_code=400, detail="Item type must be a string")
if item_type not in [possible_type.value for possible_type in ItemTypeEnum]:
if item_type_value not in [possible_type.value for possible_type in ItemTypeEnum]:
raise HTTPException(status_code=400, detail="Item type is not a valid one")
items[item_id].item_type = ItemTypeEnum[item_type]
if admin_permission != None:
items[item_id].admin_permission = admin_permission
item_type = ItemTypeEnum[item_type_value]
else:
item_type = None

item_updated = repo.update_item(item_id, name, price, item_type, admin_permission)

return {
"item_id": item_id,
"item": items[item_id].to_dict()
"item": item_updated.to_dict()
}


Expand Down
49 changes: 49 additions & 0 deletions src/app/repo/item_repository_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from abc import ABC, abstractmethod
from typing import List, Optional, Tuple

from ..enums.item_type_enum import ItemTypeEnum

from ..entities.item import Item


class IItemRepository(ABC):


@abstractmethod
def get_all_items(self) -> List[Item]:
'''
Returns all the itens in the database
'''
pass

@abstractmethod
def get_item(self, item_id: int) -> Optional[Item]:
'''
Returns the item with the given id.
If the item does not exist, returns None
'''
pass

@abstractmethod
def create_item(self, item: Item, item_id: int) -> Item:
'''
Creates a new item in the database
'''
pass

@abstractmethod
def delete_item(self, item_id: int) -> Item:
'''
Deletes the item with the given id.
If the item does not exist, returns None
'''

@abstractmethod
def update_item(self, item_id:int, name:str=None, price:float=None, item_type:ItemTypeEnum=None, admin_permission:bool=None) -> Item:
'''
Updates the item with the given id.
If the item does not exist, returns None
'''
pass


Loading

0 comments on commit 4f412d0

Please sign in to comment.