Skip to the content.

FlaskRestful

Coverage Status   codebeat badge   python3.9   framework   issues stars   license

Table of Contents

1. Require

2. Run

2.1 Docker(Recommend)

  1. install docker.
  2. cd to project directory, run make run until it is finished.
    • make run will build docker image, start server (Mysql for example).
  3. run make init to initial database (create database, create table , No data is imported).
    • go to localhost to check if it starts correctly.

Note: make test will run all unit tests in folder tests.

2.2 Shell

  1. use commands like CREATE DATABASE flask DEFAULT CHARSET utf8 or GUI tool (such as DataGrip) to create a database in your own DB server.
  2. modify SQLALCHEMY_DATABASE_URI and SQLALCHEMY_DATABASE_BASE in file settings.py to your own setting.
  3. run: ```shell script python3.11 -m venv –clear venv
    ```shell script
    source ./venv/bin/active
    

    ```shell script pip install -r requirements.txt

    ```shell script
    python server.py
    
  4. go to the localhost to check if it starts correctly.

2.3 Load Sample Data

datagrip

3. REST

4. Benefits of Rest

5. Unified Response Structure

{
    "data": data,
    "error_code": error_code,
    "error_msg": error_msg,
}

{
    "data": {
        "id": 1,
        "name": "John",
        "web_site": "https://github.com/account",
        "email": "hrui801@gmail.com",
        "create_time": "2020-05-22 13:41:49",
        "update_time": "2020-05-22 13:41:49"

    },
    "error_code": 0,
    "error_msg": "success"
}
class JsonEncoder(json.JSONEncoder):
    def default(self, value) -> Any:
        if isinstance(value, (datetime.datetime, datetime.date)):
            return value.strftime("%Y-%m-%d %H:%M:%S")
        if isinstance(value, ApiResponse):
            return value.get()
        if isinstance(value, BaseModel):
            return value.marshal()
        if isinstance(value, types.GeneratorType):
            return [self.default(v) for v in value]

        return json.JSONEncoder.default(self, value)
    app.json_encoder = JsonEncoder
def schema(query_model: BaseQueryModel, response_model: ApiDataType):
    def decorator(func):

        @wraps(func)
        def wrapper(self, **kwargs) -> Callable:
            """Some logic """
            # jsonify function is called here
            return jsonify(func(self, **kwargs))

        return wrapper

    return decorator

6. Unified Exception Handling

class ServerException(Exception):
    code = 500


class ArgumentInvalid(ServerException):
    code = 400

def handle_exception(e) -> Tuple[Dict[str, Union[Union[int, str, list], Any]], Union[int, Any]]:
    code = 500
    if isinstance(e, (HTTPException, ServerException)):
        code = e.code

    logger.exception(e)
    exc = [v for v in traceback.format_exc(limit=10).split("\n")]
    if str(code) == "500":
        send_dingding_alert(request.url, request.args, request.json, repr(e), exc)
    return {'error_code': code, 'error_msg': str(e), 'traceback': exc}, code
    app.register_error_handler(Exception, handle_exception)

7. Unified Query Model, Response Model and DataBaseModel

    def get_user(filter_obj):
    # filter_obj will have property:name, age, email
        pass
class BaseQueryModel(BaseModel):
    def __init__(self, **kwargs: dict):
        super().__init__(drop_missing=False, **kwargs)
        """ Some logic """

7.2 This Project Use Response Model for Response Results

class BaseResponseModel(BaseModel):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        """ Some logic """

7.3 This Project Use ORM for Managing Database

from flask_sqlalchemy import SQLAlchemy

class Base(db.Model, SurrogatePK):
    """DataBase Model that Contains CRUD Operations"""

    __abstract__ = True

    """Some logic that all subclass should be inherited """

7.4 This Project Use Alembic for Updating Database

from sqlalchemy.ext.declarative import declarative_base

Meta = declarative_base()
db = SQLAlchemy(model_class=Meta)

class Base(db.Model, SurrogatePK):
    """DataBase Model that Contains CRUD Operations"""

8. Swagger or Not Swagger

9. Structure of This Project

image

9.2 View (Resources in this project): Do Routing Work

9.3 Controller (Handlers in this project): Do Logic Work

9.4 Some Other Folders/Files

10. N + 1 Problem


users = User.query.limit(10) # query once

for user in users:
    posts = Post.query.filter_by(user_id==user.id)
# Query ten times
# All times Query Table is 1 + 10

11. The Downside of Rest

12. Improvements

13. Some Tools Should be Mentioned

14. A Word

@RuiCore

Contributing

PRs are accepted.

Small note: If editing the README, please conform to the standard-readme specification.

License

MIT © 2020 ruicore