File Structure - NFSandbox/sh_trade_backend GitHub Wiki
This article will introduce the basic file structure of this project.
endpoints
All files about FastAPI endpoints functions and routers.schemes
All data models and schemas should be defined here.sql.py
Specially, this file is used to store all ORM class definitions and configurations.
provider
Provide functionalities used by endpoints. For example perform database query, update data etc.database.py
Provide dependencies used by all providers related to database. For examplesession_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