This project is a web-based e-commerce platform that allows users to browse and purchase products, and provides administrators with tools for managing products, sales, and inventory. The platform is built using the FastAPI web framework and a MySQL database, and includes features such as user authentication, product categorization, and sales data analysis. The project aims to provide a scalable and maintainable solution for online retail businesses.
This project supports Python versions betweeen 3.11.1
and 3.11.3
.
fastapi
: A modern, fast (high-performance) web framework for building APIs with Python 3.7+ based on standard Python type hints.SQLAlchemy
: A SQL toolkit and ORM that provides a set of high-level API for connecting to relational databases.pydantic
: A data validation and settings management library using Python type annotations.aiomysql
: A library for accessing a MySQL database from the asyncio framework.fastapi-restful
: A library for building RESTful APIs with FastAPI.passlib
: A password hashing library for Python that provides cross-platform implementations of over 30 password hashing algorithms.pyjwt
: A Python library for encoding and decoding JSON Web Tokens (JWTs).alembic
: A lightweight database migration tool for usage with SQLAlchemy.python-dotenv
: A library for loading environment variables from a.env
file.pydantic-settings
: A library for managing application settings using Pydantic models.aiosqlite
: A library for accessing a SQLite database from the asyncio framework.pytz
: A library for working with time zones in Python.starlette-context
: A library for managing context variables in Starlette and FastAPI applications.uvicorn
: A lightning-fast ASGI server implementation, using uvloop and httptools.typing-inspect
: A library for runtime inspection of Python typing information.python-multipart
: A library for parsing multipart/form-data requests in Python.argon2-cffi
: A Python binding of the Argon2 password hashing algorithm.pandas
: A library for data manipulation and analysis.
- Clone the project repository to your local machine using
git clone <repository-url>
command. - Navigate to the project directory using
cd <project-directory>
command. - Install Poetry using the instructions provided on the official website: https://python-poetry.org/docs/#installation
- Run
poetry install
command to install the project dependencies. - Create a MySQL database and update the database connection string in the
.vars
file. You can also leave it as it is to automatically use the SQLite database included with the project. - Run the database migrations using
poetry run alembic upgrade head
command. - Start the server using
poetry run uvicorn app.main:app --reload
command.
Note: Before running the project, make sure that you have Python 3.11.1 or higher installed on your machine. Also, make sure that the required dependencies are installed using Poetry and the database connection string is updated in the .vars
file.
The project includes a populated SQLite database that can be used to play around with the APIs. While products data was hardcoded, sales data was generated using the scripts in common/data
folder.
The project uses a relational database to store data. Specifically, it uses a MySQL database with the following tables:
users
: Stores information about registered users, such as their username, email, and password hash.categories
: Stores information about product categories, such as their name and description.products
: Stores information about products, such as their name, description, price, and category ID.inventories
: Stores information about product inventory, such as the product ID, quantity, and last updated timestamp.sales
: Stores information about sales, such as the user ID, total revenue, and timestamp.sale_items
: Stores information about individual sale items, such as the sale ID, product ID, quantity, and revenue.tokens
: Stores information about authentication tokens, such as the user ID, token hash, and expiration timestamp.
The relationships between the tables are as follows:
- A user can have many sales, but a sale can only belong to one user. This is a one-to-many relationship between the
users
andsales
tables. - A sale can have many sale items, and a sale item can only belong to one sale. This is a one-to-many relationship between the
sales
andsale_items
tables. - A product can belong to one category, but a category can have many products. This is a one-to-many relationship between the
categories
andproducts
tables. - A product can have one inventory, and an inventory can only belong to one product. This is a one-to-one relationship between the
products
andinventories
tables. - A user can have many authentication tokens, and a token can only belong to one user. This is a one-to-many relationship between the
users
andtokens
tables.
The relationships are enforced using foreign key constraints in the database schema.
Please see the endpoints.json
file in the repository for a Postman/HoppScotch compatible collection to test the APIs. Furthermore, the request parameters for all endpoints are managed in api/v1/endpoints/schemas
, this is useful to get a list of possible parameters that can be forwarded to a request.
-
Register User (ecommerce/v1/register_user)
This endpoint is used to register a new user. It accepts a
PUT
request with a JSON payload containing the user's information. Therequest_schema
attribute specifies the expected schema for the request payload, which is aUserCreate
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aUser
schema.The endpoint first checks if a user with the specified email already exists in the database. If a user with the specified email exists, the endpoint returns a
422 Unprocessable Entity
response with an error message. If the user does not exist, the endpoint creates a new user in the database using thecrud.user.create
method and returns a200 OK
response with the newly created user's information in the response payload.The
authentication_required
attribute is set toFalse
, meaning that authentication is not required to access this endpoint. Theapi_name
andapi_url
attributes specify the name and URL of the endpoint, respectively. -
Login User (ecommerce/v1/login_user)
This endpoint used to log in a user. It accepts a
POST
request with a JSON payload containing the user's email and password. The endpoint first retrieves the user with the specified email from the database using thecrud.user.get_by_email
method. If a user with the specified email does not exist, the endpoint returns a422 Unprocessable Entity
response with an error message.The endpoint then verifies the user's password by comparing the hashed password stored in the database with the password provided in the request payload using the
verify_password
function. If the password does not match, the endpoint returns a422 Unprocessable Entity
response with an error message.If the user's email and password are valid, the endpoint generates an access token for the user using the
create_jwt_token
function and returns a200 OK
response with the access token in the response payload. Thetouch_last_login
method is called to update the user's last login time in the database.The
authentication_required
attribute is set toFalse
, meaning that authentication is not required to access this endpoint. -
Create Category (ecommerce/v1/create_category)
This endpoint is used to create a new category. It accepts a
PUT
request with a JSON payload containing the category's information. Therequest_schema
attribute specifies the expected schema for the request payload, which is aCreateCategoryRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aCreateCategoryResponse
schema.The endpoint first checks if a category with the specified slug already exists in the database using the
check_if_category_exists
method. If a category with the specified slug exists, the endpoint returns a422 Unprocessable Entity
response with an error message.If the category does not exist, the endpoint creates a new category in the database using the
create_category
method and returns a200 OK
response with the newly created category's information in the response payload.The
authentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint. -
Create Product (ecommerce/v1/create_product)
This endpoint is used to create a new product. It accepts a
PUT
request with a JSON payload containing the product's information. Therequest_schema
attribute specifies the expected schema for the request payload, which is aCreateProductRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aCreateProductResponse
schema.The endpoint first checks if the category specified in the request payload exists in the database using the
check_if_category_exists
method. If the category does not exist, the endpoint returns a404 Not Found
response with an error message.If the category exists, the endpoint creates a new product in the database using the
create_product
method and returns a200 OK
response with the newly created product's information in the response payload.The
authentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint. -
Get Categories (ecommerce/v1/get_categories)
This endpoint is used to retrieve a list of categories. It accepts a
GET
request with optional query parameters for pagination, sorting, and ordering. Therequest_schema
attribute specifies the expected schema for the request payload, which is aGetCategoriesRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aGetCategoriesResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint retrieves a list of categories from the database using the
crud.category.get_multi
method with the specified pagination, sorting, and ordering parameters. It then generates a200 OK
response with the list of categories in the response payload. -
Get Low Stock Products (ecommerce/v1/get_low_stock_products)
This endpoint is used to retrieve a list of low stock products. It accepts a
GET
request with a query parameter for the quantity threshold. Therequest_schema
attribute specifies the expected schema for the request payload, which is aLowStockProductsRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aLowStockProductsResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint retrieves a list of products from the database using the
crud.product.get_products_quantity_le
method with the specified quantity threshold parameter. It then generates a200 OK
response with the list of low stock products in the response payload. -
Add Inventory (ecommerce/v1/add_inventory)
This endpoint is used to add inventory to a product. It accepts a
PUT
request with a JSON payload containing the product ID and the quantity of inventory to add. Therequest_schema
attribute specifies the expected schema for the request payload, which is anAddInventoryRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is anAddInventoryResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint first checks if the product with the specified ID exists in the database using the
check_if_product_exists
method. If the product does not exist, the endpoint returns a422 Unprocessable Entity
response with an error message.If the product exists, the endpoint adds the specified quantity of inventory to the product using the
add_inventory
method and updates the product's quantity in the database using theupdate
method. It then generates a200 OK
response with the newly created inventory's information in the response payload using thegenerate_response
method. -
Get Products (ecommerce/v1/get_products)
This endpoint is used to retrieve a list of products with their associated categories. It accepts a
GET
request with optional query parameters for pagination, sorting, and ordering. Therequest_schema
attribute specifies the expected schema for the request payload, which is aGetProductsRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aGetProductsResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint retrieves a list of products with their associated categories from the database using the
crud.product.get_multi_with_category
method with the specified pagination, sorting, and ordering parameters. It then generates a200 OK
response with the list of products in the response payload. -
Purchase Products (ecommerce/v1/purchase_products)
This endpoint is used to purchase one or more products. It accepts a
POST
request with a JSON payload containing a list ofItem
objects, each representing a product to be purchased. Therequest_schema
attribute specifies the expected schema for the request payload, which is aPurchaseProductsRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aPurchaseProductsResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint first initializes two lists to keep track of successful and failed purchases. It then iterates over the list of
Item
objects in the request payload and attempts to purchase each product using thepurchase_product
method.The
purchase_product
method first retrieves the product information from the database using thecrud.product.get_active
method. If the product does not exist, the purchase is considered a failure and theItem
object is added to thefailed_purchases
list. If the product exists, the method retrieves the product's inventory information using thecrud.inventory.get_by_product_id
method. If the product's inventory is insufficient to fulfill the purchase, the purchase is considered a failure and theItem
object is added to thefailed_purchases
list. If the product's inventory is sufficient, the method creates a new sale and sale item in the database using thecrud.sale.create
andcrud.sale_item.create
methods, respectively. The product's inventory and sales data are then updated in the database using thecrud.inventory.update
andcrud.product.update
methods, respectively. The purchase is considered a success and theItem
object is added to thesuccessful_purchases
list.After all purchases have been attempted, the endpoint generates a
200 OK
response with the list of successful and failed purchases in the response payload using thegenerate_response
method. -
Get Sales Data (ecommerce/v1/get_sales_data)
This endpoint is used to retrieve sales and revenue data for a specified date range. It accepts a
GET
request with query parameters for the start and end dates, product IDs, category IDs, and bucketing options. Therequest_schema
attribute specifies the expected schema for the request payload, which is aGetSalesDataRequest
schema. Theresponse_schema
attribute specifies the expected schema for the response payload, which is aGetSalesDataResponse
schema. Theauthentication_required
attribute is set toTrue
, meaning that authentication is required to access this endpoint.The endpoint first retrieves the sales data from the database using the
crud.sale.get_sales_data
method with the specified request parameters. It then calculates the revenue for each sale and stores the sales data as a list of dictionaries.If the
buckets
parameter is specified, the endpoint creates buckets based on the specified time interval (daily, weekly, monthly, or yearly) using thecreate_buckets
method. It then populates the sales data into the appropriate bucket based on the sale date using thepopulate_buckets
method. If theinclude_sales_items
parameter is set toTrue
, the endpoint also adds the sale to thesales
list for that bucket.If the
buckets
parameter is not specified, the endpoint populates the sales data without the bucketing logic using thepopulate_metrics
method.The endpoint generates a
200 OK
response with the sales and revenue data in the response payload using thegenerate_response
method.