Mock响应插件

在开发流程中,后端开发者往往都会先定义API文档并通过API文档与前端开发者讨论API的实现并进行修改,在这个阶段中API并没有具体的实现。 在这个阶段中,前后端开发者会同时进行开发,那么就有可能会出现前端开发者在开发过程中需要对API进行调试,但由于后端开发者尚未开发完成前端开发者导致无法调试的情况。

为此,可以通过Mock插件为没有实现逻辑的路由函数返回指定的响应数据,如下:

docs_source_code/docs_source_code/plugin/mock_plugin/flask_with_mock_plugin_demo.py
from typing import List, Type

from flask import Flask
from pydantic import BaseModel, Field

from pait.app.flask import pait
from pait.app.flask.plugin import MockPlugin
from pait.field import Query
from pait.model.response import JsonResponseModel


class UserSuccessRespModel2(JsonResponseModel):
    class ResponseModel(BaseModel):
        class DataModel(BaseModel):
            uid: int = Field(description="user id", gt=10, lt=1000, example=666)
            user_name: str = Field(example="mock_name", description="user name", min_length=2, max_length=10)
            multi_user_name: List[str] = Field(
                example=["mock_name"], description="user name", min_length=1, max_length=10
            )
            age: int = Field(example=99, description="age", gt=1, lt=100)
            email: str = Field(example="example@so1n.me", description="user email")

        code: int = Field(0, description="api code")
        msg: str = Field("success", description="api status msg")
        data: DataModel

    description: str = "success response"
    response_data: Type[BaseModel] = ResponseModel


@pait(response_model_list=[UserSuccessRespModel2], plugin_list=[MockPlugin.build()])
def demo(
    uid: int = Query.i(description="user id", gt=10, lt=1000),
    user_name: str = Query.i(description="user name", min_length=2, max_length=4),
    email: str = Query.i(default="example@xxx.com", description="user email"),
) -> dict:
    return {}


app = Flask("demo")
app.add_url_rule("/api/demo", view_func=demo, methods=["GET"])


if __name__ == "__main__":
    app.run(port=8000)
docs_source_code/docs_source_code/plugin/mock_plugin/starlette_with_mock_plugin_demo.py
from typing import List, Type

from pydantic import BaseModel, Field
from starlette.applications import Starlette
from starlette.routing import Route

from pait.app.starlette import pait
from pait.app.starlette.plugin import MockPlugin
from pait.field import Query
from pait.model.response import JsonResponseModel


class UserSuccessRespModel2(JsonResponseModel):
    class ResponseModel(BaseModel):
        class DataModel(BaseModel):
            uid: int = Field(description="user id", gt=10, lt=1000, example=666)
            user_name: str = Field(example="mock_name", description="user name", min_length=2, max_length=10)
            multi_user_name: List[str] = Field(
                example=["mock_name"], description="user name", min_length=1, max_length=10
            )
            age: int = Field(example=99, description="age", gt=1, lt=100)
            email: str = Field(example="example@so1n.me", description="user email")

        code: int = Field(0, description="api code")
        msg: str = Field("success", description="api status msg")
        data: DataModel

    description: str = "success response"
    response_data: Type[BaseModel] = ResponseModel


@pait(response_model_list=[UserSuccessRespModel2], plugin_list=[MockPlugin.build()])
async def demo(
    uid: int = Query.i(description="user id", gt=10, lt=1000),
    user_name: str = Query.i(description="user name", min_length=2, max_length=4),
    email: str = Query.i(default="example@xxx.com", description="user email"),
) -> dict:
    return {}


app = Starlette(routes=[Route("/api/demo", demo, methods=["GET"])])


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)
docs_source_code/docs_source_code/plugin/mock_plugin/sanic_with_mock_plugin_demo.py
from typing import List, Type

from pydantic import BaseModel, Field
from sanic import Sanic

from pait.app.sanic import pait
from pait.app.sanic.plugin import MockPlugin
from pait.field import Query
from pait.model.response import JsonResponseModel


class UserSuccessRespModel2(JsonResponseModel):
    class ResponseModel(BaseModel):
        class DataModel(BaseModel):
            uid: int = Field(description="user id", gt=10, lt=1000, example=666)
            user_name: str = Field(example="mock_name", description="user name", min_length=2, max_length=10)
            multi_user_name: List[str] = Field(
                example=["mock_name"], description="user name", min_length=1, max_length=10
            )
            age: int = Field(example=99, description="age", gt=1, lt=100)
            email: str = Field(example="example@so1n.me", description="user email")

        code: int = Field(0, description="api code")
        msg: str = Field("success", description="api status msg")
        data: DataModel

    description: str = "success response"
    response_data: Type[BaseModel] = ResponseModel


@pait(response_model_list=[UserSuccessRespModel2], plugin_list=[MockPlugin.build()])
async def demo(
    uid: int = Query.i(description="user id", gt=10, lt=1000),
    user_name: str = Query.i(description="user name", min_length=2, max_length=4),
    email: str = Query.i(default="example@xxx.com", description="user email"),
) -> dict:
    return {}


app = Sanic("demo")
app.add_route(demo, "/api/demo", methods=["GET"])


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)
docs_source_code/docs_source_code/plugin/mock_plugin/tornado_with_mock_plugin_demo.py
from typing import List, Type

from pydantic import BaseModel, Field
from tornado.ioloop import IOLoop
from tornado.web import Application, RequestHandler

from pait.app.tornado import pait
from pait.app.tornado.plugin import MockPlugin
from pait.field import Query
from pait.model.response import JsonResponseModel


class UserSuccessRespModel2(JsonResponseModel):
    class ResponseModel(BaseModel):
        class DataModel(BaseModel):
            uid: int = Field(description="user id", gt=10, lt=1000, example=666)
            user_name: str = Field(example="mock_name", description="user name", min_length=2, max_length=10)
            multi_user_name: List[str] = Field(
                example=["mock_name"], description="user name", min_length=1, max_length=10
            )
            age: int = Field(example=99, description="age", gt=1, lt=100)
            email: str = Field(example="example@so1n.me", description="user email")

        code: int = Field(0, description="api code")
        msg: str = Field("success", description="api status msg")
        data: DataModel

    description: str = "success response"
    response_data: Type[BaseModel] = ResponseModel


class DemoHandler(RequestHandler):
    @pait(response_model_list=[UserSuccessRespModel2], plugin_list=[MockPlugin.build()])
    async def get(
        uid: int = Query.i(description="user id", gt=10, lt=1000),
        user_name: str = Query.i(description="user name", min_length=2, max_length=4),
        email: str = Query.i(default="example@xxx.com", description="user email"),
    ) -> dict:
        return {}


app: Application = Application([(r"/api/demo", DemoHandler)])


if __name__ == "__main__":
    app.listen(8000)
    IOLoop.instance().start()

这份代码先是实现了一个名为UserSuccessRespModel2的响应对象,这个响应对象与之前的响应对象有一些不同的是它的部分字段拥有example属性。 接着创建一个没有任何代码逻辑的demo路由函数,这个函数只拥有一些参数,同时通过pait使用了Mock插件以及UserSuccessRespModel2响应对象。

运行代码并执行如下命令,通过输出结果可以看到在使用了Mock插件后,路由函数能够正常返回数据且数据与UserSuccessRespModel2响应对象中example的值是一样的:

  curl http://127.0.0.1:8000/api/demo
{"code":0,"data":{"age":99,"email":"example@so1n.me","multi_user_name":["mock_name"],"uid":666,"user_name":"mock_name"},"msg":"success"}

Note

  • 1.example也支持工厂函数,此时它与default_factory效果类似。可填写的值如example=time.nowexample=lambda :random.randint(100000, 900000)等。
  • 2.Mock插件支持通过参数example_column_name定义默认值字段,默认为example,也可以是mock