diff --git a/.gitignore b/.gitignore index 85e7c1dfcb7fbb33f932c81024018cd8c10519da..7276a7e37063a2a502fe981d506dda3ebea7310d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ /.idea/ +*.pyc +*.log +logs/ +__pycache__/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..f84534d6dfd8e803cf65f2f08991122bb87a5e8f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python3: FastAPI", + "type": "python", + "request": "launch", + "module": "uvicorn", + "args": [ + "main:app" + ], + "jinja": true, + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index fe8e0777038d99947b79e9d2156f308263d8c30a..5544ec3d502b26aeed3f1a6843d651dab560bbd7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ FASTAPI -=== +======= ![](https://img.shields.io/badge/Python-3.6%2B-green) @@ -14,8 +14,7 @@ FastAPI framework, high performance, easy to learn, fast to code, ready for prod 3. 数据库的插入操作 4. 全局异常处理 - -### +### Documentation: https://fastapi.tiangolo.com 中文文档:https://fastapi.tiangolo.com/zh/ @@ -24,13 +23,15 @@ Source Code: https://github.com/tiangolo/fastapi # 组件 -技术 | 说明 | 官网 -----|-----------------------------------------------------------------------------------------|---- -fastapi | web server | https://fastapi.tiangolo.com/ -uvicorn | web容器 | https://www.uvicorn.org/ - PySnooper| 调试,展示调用详情 | https://github.com/cool-RR/PySnooper -ujson | an ultra fast JSON encoder and decoder written in pure C with bindings for Python 3.7+. | https://github.com/ultrajson/ultrajson -Pydantic | 基于标准的 Python 3.6 类型声明 | https://pydantic-docs.helpmanual.io/ + +| 技术 | 说明 | 官网 | +| ----------- | ----------------------------------------------------------------------------------------- | ---------------------------------------- | +| fastapi | web server | https://fastapi.tiangolo.com/ | +| uvicorn | web容器 | https://www.uvicorn.org/ | +| PySnooper | 调试,展示调用详情 | https://github.com/cool-RR/PySnooper | +| ujson | an ultra fast JSON encoder and decoder written in pure C with bindings for Python 3.7+. | https://github.com/ultrajson/ultrajson | +| Pydantic | 基于标准的 Python 3.6 类型声明 | https://pydantic-docs.helpmanual.io/ | + ### 安装fastapi ```shell @@ -45,14 +46,15 @@ pip install fastapi pip install uvicorn ``` - - ### 运行程序 + 下面这种非常规启动程序与java的war包丢在tomcat里面一样。本质上差不多。而且效果可能更好,可以自动热重启。 + ```shell uvicorn main:app --reload ``` -![](asset/img/run.png) + +![](assets/img/run.png) #### 热重启 @@ -63,26 +65,33 @@ uvicorn main:app --reload #### main方法运行 下面这种与上面没有本质区别。 + ```python import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ``` + [FastAPI 开始安装(创建第一个例子)多种运行方式](https://blog.csdn.net/qq_40815295/article/details/106896707) [官网提供这种运行方式](https://fastapi.tiangolo.com/zh/tutorial/debugging/) - ### 自带文档 Swagger UI : http://127.0.0.1:8000/docs#/ 或者 - + ReDoc : http://127.0.0.1:8000/redoc openapi:http://127.0.0.1:8000/openapi.json -![](asset/img/fastapi-swagger.png) +![](assets/img/fastapi-swagger.png) + +![img.png](assets/img/img.png) + +![img_1.png](assets/img/img_1.png) + + +# 日志文件跳转 -![img.png](asset/img/img.png) -![img_1.png](asset/img/img_1.png) \ No newline at end of file +![](assets/20221228_195511_image.png) diff --git a/assets/20221228_195511_image.png b/assets/20221228_195511_image.png new file mode 100644 index 0000000000000000000000000000000000000000..06dc20783e035bc0bf1a2ca3f7e68cb50c771a75 Binary files /dev/null and b/assets/20221228_195511_image.png differ diff --git a/asset/img/fastapi-swagger.png b/assets/img/fastapi-swagger.png similarity index 100% rename from asset/img/fastapi-swagger.png rename to assets/img/fastapi-swagger.png diff --git a/asset/img/img.png b/assets/img/img.png similarity index 100% rename from asset/img/img.png rename to assets/img/img.png diff --git a/asset/img/img_1.png b/assets/img/img_1.png similarity index 100% rename from asset/img/img_1.png rename to assets/img/img_1.png diff --git a/asset/img/run.png b/assets/img/run.png similarity index 100% rename from asset/img/run.png rename to assets/img/run.png diff --git a/main.py b/main.py index 38fa5f3622bb1d19d224830c2654718356defcc0..d3258dca881a3ac9bba5e479b8fce8bcf656d12f 100644 --- a/main.py +++ b/main.py @@ -4,12 +4,14 @@ from concurrent.futures.thread import ThreadPoolExecutor import pysnooper import uvicorn from fastapi import FastAPI, Query, status, Depends -from loguru import logger +from src.config.log_config import logger +from src.config.common_config import SERVER_PORT + +from src.dao import models +from src.dao.database import engine +from src.routers import users, items +from src.dependencies import get_token_header -from dao import models -from dao.database import engine -from routers import users, items -from dependencies import get_token_header # 创建一个包含3条线程的线程池 pool = ThreadPoolExecutor(max_workers=3) @@ -75,4 +77,4 @@ def mq_start(): if __name__ == '__main__': logger.debug("程序开始启动") - uvicorn.run(app=app, host="0.0.0.0", port=8000) + uvicorn.run(app=app, host="0.0.0.0", port=SERVER_PORT) diff --git a/requirements.txt b/requirements.txt index ff6a6f538fba41831f91ac94b0cc3138ffbb34ce..e0d7878512e2b0d0aa478cf41b8774e031b205c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -fastapi~=0.72.0 +fastapi~=0.88.0 loguru~=0.5.3 uvicorn~=0.17.0 pysnooper~=1.1.0 diff --git a/src/config/__init__.py b/src/config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2c53b5d9b220f68f77af546524461d5db0445a2b --- /dev/null +++ b/src/config/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +""" +@Author : Pink +@Time : 4/6/2022 10:30 AM +@Function: +""" +from configparser import ConfigParser +import os + +dirname = os.path.dirname(__file__) + '/config_data' +configuration = ConfigParser() + + +def read_config(active: str): + """ + 读取配置文件 + active: 环境名称 dev/beta/prod + """ + print("app current profile active : %s" % active) + ini_file: str = dirname + "/app_config_" + active + ".ini" + if not os.path.exists(ini_file): + # 读取默认文件 + ini_file: str = dirname + "/app_config_dev.ini" + configuration.read(ini_file, encoding='utf-8') + + +read_config('prod') diff --git a/src/config/common_config.py b/src/config/common_config.py new file mode 100644 index 0000000000000000000000000000000000000000..c0819225bd13b65674fad3802e45b120ed1787dc --- /dev/null +++ b/src/config/common_config.py @@ -0,0 +1,19 @@ +from src.config import configuration + +# server +SERVER_PORT = configuration.getint('server', 'PORT') + +# ===== Log Config ===== +LOG_RETENTION = configuration.get('log', 'LOG_RETENTION') +LOG_ROTATION = configuration.get('log', 'LOG_ROTATION') +LOG_TO_CONSOLE = configuration.getboolean('log', 'LOG_TO_CONSOLE') +LOG_TO_FILE = configuration.getboolean('log', 'LOG_TO_FILE') +LOG_LEVEL = configuration.get('log', 'LOG_LEVEL') + +LOG_FORMAT = "{time:YYYY-MM-DD HH:mm:ss.SSS} | " \ + "{level} | " \ + "{process.name} | " \ + "{thread.name} | " \ + "{module}.{function}:" \ + "{message}" \ + " File \"{file.path}\", line {line} " \ No newline at end of file diff --git a/src/config/config_data/app_config_dev.ini b/src/config/config_data/app_config_dev.ini new file mode 100644 index 0000000000000000000000000000000000000000..d7c8652afb45c6a9cc453cde7d12a495b5d11507 --- /dev/null +++ b/src/config/config_data/app_config_dev.ini @@ -0,0 +1,14 @@ +[server] +PORT=8000 + +[log] +; 日志过期时间, 此处需要按照 天数+空格+days 的格式,如[30 days] +LOG_RETENTION = 30 days +; 文件划分依据,每天12点 +LOG_ROTATION = 00:00 +; 是否输出到控制台 +LOG_TO_CONSOLE = True +; 是否输出到文件 +LOG_TO_FILE = True +; 日志等级 +LOG_LEVEL = INFO \ No newline at end of file diff --git a/src/config/log_config.py b/src/config/log_config.py new file mode 100644 index 0000000000000000000000000000000000000000..21de8c8aea377d8b1dc76889ec67e71cc46e73f2 --- /dev/null +++ b/src/config/log_config.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +""" +@Author : Pink +@Time : 2022/9/22 15:14 +@Description : +""" +import os +import sys +import loguru +from src.config.common_config import LOG_TO_CONSOLE, LOG_RETENTION, LOG_ROTATION, LOG_LEVEL, LOG_TO_FILE, LOG_FORMAT + + +class LogUtils: + __instance = None + __logs = [] + + def __new__(cls, *args, **kwargs): + if not cls.__instance: + cls.__instance = super().__new__(cls) + return cls.__instance + + def __init__(self, log_name=''): + self.log = loguru.logger + if log_name not in self.__logs: + log_dir = os.path.expanduser('logs') + if not os.path.exists(log_dir): os.makedirs(log_dir) + log_file_info = os.path.join(log_dir, '{}_info.log'.format(log_name)) + log_file_error = os.path.join(log_dir, '{}_error.log'.format(log_name)) + if not LOG_TO_CONSOLE: + self.log.remove(handler_id=None) + else: + self.log.remove() + self.log.add(sink=sys.stdout, + format=LOG_FORMAT, + level=LOG_LEVEL) + if LOG_TO_FILE: + self.log.add(sink=log_file_info, + retention=LOG_RETENTION, + rotation=LOG_ROTATION, + enqueue=True, + format=LOG_FORMAT, + level=LOG_LEVEL) + self.log.add(sink=log_file_error, + retention=LOG_RETENTION, + rotation=LOG_ROTATION, + enqueue=True, + level="WARNING") + self.__logs.append(log_name) + + def get_logger(self): + return self.log + + +logger = LogUtils("fastapi-server").get_logger() diff --git a/dao/__init__.py b/src/dao/__init__.py similarity index 100% rename from dao/__init__.py rename to src/dao/__init__.py diff --git a/dao/crud.py b/src/dao/crud.py similarity index 100% rename from dao/crud.py rename to src/dao/crud.py diff --git a/dao/database.py b/src/dao/database.py similarity index 100% rename from dao/database.py rename to src/dao/database.py diff --git a/dao/models.py b/src/dao/models.py similarity index 100% rename from dao/models.py rename to src/dao/models.py diff --git a/dao/schemas.py b/src/dao/schemas.py similarity index 100% rename from dao/schemas.py rename to src/dao/schemas.py diff --git a/dependencies.py b/src/dependencies.py similarity index 100% rename from dependencies.py rename to src/dependencies.py diff --git a/routers/__init__.py b/src/routers/__init__.py similarity index 100% rename from routers/__init__.py rename to src/routers/__init__.py diff --git a/routers/items.py b/src/routers/items.py similarity index 97% rename from routers/items.py rename to src/routers/items.py index d9aafa99d39404bed358cfca7f81ebf8dcfd657e..9e85a7b5384748774c3557199abd323c06fc5f5a 100644 --- a/routers/items.py +++ b/src/routers/items.py @@ -3,7 +3,7 @@ from loguru import logger from pydantic import BaseModel from typing import Optional -from dependencies import get_token_header +from src.dependencies import get_token_header router = APIRouter( prefix="/items", diff --git a/routers/users.py b/src/routers/users.py similarity index 92% rename from routers/users.py rename to src/routers/users.py index 8f902cb16d81f5162caaeeae00a77be1870c1958..e8b24f79062cc50b99d8f87801ed42d522698e98 100644 --- a/routers/users.py +++ b/src/routers/users.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, HTTPException, Depends -from dao import schemas, crud -from dao.database import SessionLocal +from src.dao import schemas, crud +from src.dao.database import SessionLocal from sqlalchemy.orm import Session router = APIRouter() diff --git a/src/webapp.py b/src/webapp.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/api/local.http b/test/api/local.http index fd3cfe78d6d7b0fba5b6d67c08ab22f68fbf34da..65d3adcf82f4292e3e29fa2c0973344dbaffebf5 100644 --- a/test/api/local.http +++ b/test/api/local.http @@ -1,5 +1,5 @@ GET http://localhost:8000 - +x_token:fake-super-secret-token ### GET http://localhost:8000/hello/eric