This is a template to follow when creating APIs
- Navigate to root directory
- Run with
docker-compose up -d
Assumes you're using PyCharm
- Navigate to root directory
- Start database in docker with
docker-compose run -d --service-ports db - Create a new virtual environment at
.venv - Navigate to root directory
- Activate virtual environment with
source .venv/bin/activate - Install requirements with
pip install -r src/requirements.txt - Create new Python run configuration
script->[root]/src/app.py
- Run
In a browser, hit http://localhost:5000/healthcheck.
If everything is running properly, this should return Success
src
+ clients # clients for third party integrations go here
+ daos # daos go here
+ endpoints # endpoints go here
+ migrations # migration scripts go
+ models # models (ORM, DTO, etc) go here
+ services # business logic goes here
The most common flow of information we'll use for endpoints is:
endpoint layer --> services layer --> database (dao) layer
The endpoint layer parses information from the API request and sends it to the services layer.
- When a service layer function is called, it doesn't know where the parameters came from.
That's beyond the scope of its responsibilities.
In fact, it doesn't even know that the
endpointslayer exists.
Then the services layer calls a function in the database layer to fetch some stored information.
- When the database layer returns data, the service layer doesn't know where it came from. That's beyond the scope of its responsibilities.
- On the flip side, when the database layer returns data, it doesn't know or care what's being done with that information. That's beyond the scope of its responsibilities.
This modularity is powerful when we need to make changes. If we need to change the way we're getting data from the database, we only need to make updates to the database layer. None of the other modules know or care what's happening, as long as it gets the data that it expects.
This folder contains all the logic for communicating with third party applications.
- Make API requests to other services
- Parse API responses into native models
- Handle business logic
- Access the database
This folder contains all of your Database Access Objects (DAOs).
Each DAO should have its own file, and each model / domain should have its own DAO.
When dealing with objects, a DAO should always accept (as parameters) and return DTOs (data transfer object).
In other words, only the DAO's internal functions should see ORM models.
if the above section is confusing, see the models section
In addition, each DAO should inherit from BaseDAO.
This offers a few pre-made functions which should cover most basic database functionality:
insertinsertmanyfetchonefetchallfetchfirstdeleteupdate
- Make database queries
- Handle conversion from
ORMtoDTOtypes
- Declare endpoints
- Interact with other
DAOs - Handle business logic
This folder contains all the Flask Blueprints for your API. Each blueprint should have its own file.
- Declare blueprints
- Declare endpoints
- Input parsing / validation
- Handle business logic
- Access the database
This folder contains all the migration scripts (in SQL) for your database. Filenames must start with the current date (YYYYMMDD) to preserve order.
Important: All database updates must be explicitly written here. This is how we keep track of the database's state. Do not ever make changes to production databases without writing the scripts here first.
This folder contains all the models used in your API.
There are three types of models:
DTO(Data Transfer Object)- Ex:
UserDTO - Contains all information about a certain model
- Passed around internally
- Inherits from
BaseDTO
- Ex:
ORM(Object Relational Mapping)- Ex:
UserORM - Maps directly to the columns of a database table
- Used only in the DAO layer
- Inherits from
BaseORM
- Ex:
- And, the normal model
- Ex:
User - This is the model that is sent out in API responses
- Contains some or all of the same information that a
DTOhas- But may omit some fields because they contain sensitive or irrelevant data (ex: birthday)
- Ex:
ORM models also come with a method, to_dto().
This is used by DAOs to convert from ORMs to DTOs.
BaseORM provides a built-in method for it which maps fields between DTO and ORM 1:1.
However, more complex models (ex: models with foreign keys involved) may require override methods.
- Initialize and make calls to
DAOs - Process data
- Access the database directly
- Declare endpoints
- Parse HTTP request data
This folder contains all the business logic for your API. Each domain should have its own file.
- Initialize and make calls to
DAOs - Initialize and make calls to
clients - Initialize and make calls to other
servicesonly when truly necessary - Process data
- Access the database directly
- Declare endpoints
- Parse HTTP request data