File Structure - NFSandbox/sh_trade_backend GitHub Wiki
This article will introduce the basic file structure of this project.
- endpointsAll files about FastAPI endpoints functions and routers.
- schemesAll data models and schemas should be defined here.- sql.pySpecially, this file is used to store all ORM class definitions and configurations.
 
- providerProvide functionalities used by endpoints. For example perform database query, update data etc.- database.pyProvide dependencies used by all providers related to database. For example- session_maker()
 
Endpoint
The endpoints directory only takes charges in:
- Data Validation
- Basic Authentication (By using some depencency with auth feature)
- Expose funcionality
The business logic itself is not implemented in the endpoint functions. Instead, we move that part into the functions in provider. So generally, an endpoint  function will need to call some other functions in provider to perform operations or retrieve data.
Using get all user items as example:
(endpoints) get_user_item(): Get current user from cookies
(endpoints) get_user_item(): Check all parameters are valid
(endpoints) get_user_item(): Check user is not banned
(endpoints) get_user_item(): Call get_items_from_user() in provider
(provider)  get_items_from_user(): Execute database query, remove soft deleted result
(provider)  get_items_from_user(): Return result
(endpoints) get_user_item(): validate return value, return to user
Provider
provider directory is one of the functionality core directory of this project. All database operations and any other possible feature provided by this API is finally implemented here in this directory.
Providers usually work with endpoint functions. For more info, check out Endpoints part.
Double Layer Provider
All functionalities are implemented in Providers, and one provider may depends on functions in other providers, which may lead to Circular Dependencies in Python.
In order to prevent Circular Dependencies in providers, we need to elevate the Core Functions into core layer of the providers, which lies in provider.[part].core
Here, Core Functions means the functions which may be used by other providers. For example:
For example:
- provider.user.get_user_by_id()- Should be elevated to provider.user.core.user.get_user_by_id()
 
- Should be elevated to 
In this case, the file structure would be:
- provider/- [part]/- __init__.py
- [part].py
- core.py
 
- [other_part]/- …
 
 
Also, the [part].core module could be imported in [part] package:
# in [part].__init__.py
from .core import *
from .[part] import *
By doing this, we could directly use functions in core while import [part] package as a whole:
from provider import [part]
[part].some_function_in_part_core()
Check out the diagram below for a better understanding of this double-layer providers structure.
When using core functions in other providers, we need to directly import the provider.[part].core package instead of provider.[part], for example:
# do NOT do this
from provider.user import get_user_by_id
# instead, do this
from provider.user.core import get_user_by_id