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.envfile.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 installcommand to install the project dependencies. - Create a MySQL database and update the database connection string in the
.varsfile. 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 headcommand. - Start the server using
poetry run uvicorn app.main:app --reloadcommand.
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
usersandsalestables. - 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
salesandsale_itemstables. - A product can belong to one category, but a category can have many products. This is a one-to-many relationship between the
categoriesandproductstables. - A product can have one inventory, and an inventory can only belong to one product. This is a one-to-one relationship between the
productsandinventoriestables. - 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
usersandtokenstables.
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
PUTrequest with a JSON payload containing the user's information. Therequest_schemaattribute specifies the expected schema for the request payload, which is aUserCreateschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aUserschema.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 Entityresponse with an error message. If the user does not exist, the endpoint creates a new user in the database using thecrud.user.createmethod and returns a200 OKresponse with the newly created user's information in the response payload.The
authentication_requiredattribute is set toFalse, meaning that authentication is not required to access this endpoint. Theapi_nameandapi_urlattributes 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
POSTrequest 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_emailmethod. If a user with the specified email does not exist, the endpoint returns a422 Unprocessable Entityresponse 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_passwordfunction. If the password does not match, the endpoint returns a422 Unprocessable Entityresponse 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_tokenfunction and returns a200 OKresponse with the access token in the response payload. Thetouch_last_loginmethod is called to update the user's last login time in the database.The
authentication_requiredattribute 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
PUTrequest with a JSON payload containing the category's information. Therequest_schemaattribute specifies the expected schema for the request payload, which is aCreateCategoryRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aCreateCategoryResponseschema.The endpoint first checks if a category with the specified slug already exists in the database using the
check_if_category_existsmethod. If a category with the specified slug exists, the endpoint returns a422 Unprocessable Entityresponse with an error message.If the category does not exist, the endpoint creates a new category in the database using the
create_categorymethod and returns a200 OKresponse with the newly created category's information in the response payload.The
authentication_requiredattribute 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
PUTrequest with a JSON payload containing the product's information. Therequest_schemaattribute specifies the expected schema for the request payload, which is aCreateProductRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aCreateProductResponseschema.The endpoint first checks if the category specified in the request payload exists in the database using the
check_if_category_existsmethod. If the category does not exist, the endpoint returns a404 Not Foundresponse with an error message.If the category exists, the endpoint creates a new product in the database using the
create_productmethod and returns a200 OKresponse with the newly created product's information in the response payload.The
authentication_requiredattribute 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
GETrequest with optional query parameters for pagination, sorting, and ordering. Therequest_schemaattribute specifies the expected schema for the request payload, which is aGetCategoriesRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aGetCategoriesResponseschema. Theauthentication_requiredattribute 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_multimethod with the specified pagination, sorting, and ordering parameters. It then generates a200 OKresponse 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
GETrequest with a query parameter for the quantity threshold. Therequest_schemaattribute specifies the expected schema for the request payload, which is aLowStockProductsRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aLowStockProductsResponseschema. Theauthentication_requiredattribute 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_lemethod with the specified quantity threshold parameter. It then generates a200 OKresponse 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
PUTrequest with a JSON payload containing the product ID and the quantity of inventory to add. Therequest_schemaattribute specifies the expected schema for the request payload, which is anAddInventoryRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is anAddInventoryResponseschema. Theauthentication_requiredattribute 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_existsmethod. If the product does not exist, the endpoint returns a422 Unprocessable Entityresponse with an error message.If the product exists, the endpoint adds the specified quantity of inventory to the product using the
add_inventorymethod and updates the product's quantity in the database using theupdatemethod. It then generates a200 OKresponse with the newly created inventory's information in the response payload using thegenerate_responsemethod. -
Get Products (ecommerce/v1/get_products)
This endpoint is used to retrieve a list of products with their associated categories. It accepts a
GETrequest with optional query parameters for pagination, sorting, and ordering. Therequest_schemaattribute specifies the expected schema for the request payload, which is aGetProductsRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aGetProductsResponseschema. Theauthentication_requiredattribute 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_categorymethod with the specified pagination, sorting, and ordering parameters. It then generates a200 OKresponse 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
POSTrequest with a JSON payload containing a list ofItemobjects, each representing a product to be purchased. Therequest_schemaattribute specifies the expected schema for the request payload, which is aPurchaseProductsRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aPurchaseProductsResponseschema. Theauthentication_requiredattribute 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
Itemobjects in the request payload and attempts to purchase each product using thepurchase_productmethod.The
purchase_productmethod first retrieves the product information from the database using thecrud.product.get_activemethod. If the product does not exist, the purchase is considered a failure and theItemobject is added to thefailed_purchaseslist. If the product exists, the method retrieves the product's inventory information using thecrud.inventory.get_by_product_idmethod. If the product's inventory is insufficient to fulfill the purchase, the purchase is considered a failure and theItemobject is added to thefailed_purchaseslist. If the product's inventory is sufficient, the method creates a new sale and sale item in the database using thecrud.sale.createandcrud.sale_item.createmethods, respectively. The product's inventory and sales data are then updated in the database using thecrud.inventory.updateandcrud.product.updatemethods, respectively. The purchase is considered a success and theItemobject is added to thesuccessful_purchaseslist.After all purchases have been attempted, the endpoint generates a
200 OKresponse with the list of successful and failed purchases in the response payload using thegenerate_responsemethod. -
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
GETrequest with query parameters for the start and end dates, product IDs, category IDs, and bucketing options. Therequest_schemaattribute specifies the expected schema for the request payload, which is aGetSalesDataRequestschema. Theresponse_schemaattribute specifies the expected schema for the response payload, which is aGetSalesDataResponseschema. Theauthentication_requiredattribute 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_datamethod 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
bucketsparameter is specified, the endpoint creates buckets based on the specified time interval (daily, weekly, monthly, or yearly) using thecreate_bucketsmethod. It then populates the sales data into the appropriate bucket based on the sale date using thepopulate_bucketsmethod. If theinclude_sales_itemsparameter is set toTrue, the endpoint also adds the sale to thesaleslist for that bucket.If the
bucketsparameter is not specified, the endpoint populates the sales data without the bucketing logic using thepopulate_metricsmethod.The endpoint generates a
200 OKresponse with the sales and revenue data in the response payload using thegenerate_responsemethod.