Parameter checking plugin
Pait
is based on Pydantic
to perform parameter checking and type conversion for each parameter,
which cannot satisfy the need for multiple parameter dependency checking.
For this reason,
Pait
provides two kinds of parameter dependency checking functions through post plugins Required
and AtMostOneOf
.
1.Required Plugin
In the creation of route functions, often encounter some parameter dependencies,
such as having a request parameter A, B, C,
which B and C are optional and the requirement that B exists, C also needs to exist, B does not exist, C can not exist.
At this point, you can use the Required
plugin for parameter restriction, the following code:
Flask Starlette Sanic Tornado
docs_source_code/plugin/param_plugin/flask_with_required_plugin_demo.py from typing import Optional
from flask import Flask , Response , jsonify
from pait import field
from pait.app.flask import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredPlugin
def api_exception ( exc : Exception ) -> Response :
if isinstance ( exc , TipException ):
exc = exc . exc
return jsonify ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ( required_dict = { "email" : [ "user_name" ]})])
def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> Response :
return jsonify ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Flask ( "demo" )
app . add_url_rule ( "/api/demo" , view_func = demo , methods = [ "GET" ])
app . errorhandler ( Exception )( api_exception )
if __name__ == "__main__" :
app . run ( port = 8000 )
docs_source_code/plugin/param_plugin/starlette_with_required_plugin_demo.py from typing import Optional
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from pait import field
from pait.app.starlette import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> JSONResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return JSONResponse ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ( required_dict = { "email" : [ "user_name" ]})])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> JSONResponse :
return JSONResponse ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Starlette ( routes = [ Route ( "/api/demo" , demo , methods = [ "GET" ])])
app . add_exception_handler ( Exception , api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/sanic_with_required_plugin_demo.py from typing import Optional
from sanic import Request , Sanic
from sanic.response import HTTPResponse , json
from pait import field
from pait.app.sanic import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> HTTPResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return json ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ( required_dict = { "email" : [ "user_name" ]})])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> HTTPResponse :
return json ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Sanic ( "demo" )
app . add_route ( demo , "/api/demo" , methods = [ "GET" ])
app . exception ( Exception )( api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/tornado_with_required_plugin_demo.py from typing import Optional
from tornado.ioloop import IOLoop
from tornado.web import Application , RequestHandler
from pait import field
from pait.app.tornado import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredPlugin
class _Handler ( RequestHandler ):
def _handle_request_exception ( self , exc : BaseException ) -> None :
if isinstance ( exc , TipException ):
exc = exc . exc
self . write ({ "data" : str ( exc )})
self . finish ()
class DemoHandler ( _Handler ):
@pait ( post_plugin_list = [ RequiredPlugin . build ( required_dict = { "email" : [ "user_name" ]})])
async def get (
self ,
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> None :
self . write ({ "uid" : uid , "user_name" : user_name , "email" : email })
app : Application = Application ([( r "/api/demo" , DemoHandler )])
if __name__ == "__main__" :
app . listen ( 8000 )
IOLoop . instance () . start ()
The parameter uid
is a required parameter in the route function, while the parameters user_name
and email
are optional,
but a new validation rule is added when the ReuiredPlugin
plugin is used.
This validation rule is defined by required_dict
, which states that the parameter email
must depend on a collection of parameters to exist,
and that collection has only one parameter -- user_name
.
So the validation rule for RequiredPlugin
is that the parameter email
can only exist if the parameter user_name
exists.
After using curl
to send a request through the response results can be found,
if the request parameter is only uid
can be returned normally, but the request parameter user_name
is null,
the parameter email
must be null, otherwise it will report an error.
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123
{ "uid" :"123" ,"user_name" :null,"email" :null} %
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123 \& email\= aaa
{ "data" :"email requires param user_name, which if not none" } %
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123 \& email\= aaa\& user_name\= so1n
{ "uid" :"123" ,"user_name" :"so1n" ,"email" :"aaa" } %
The Required
plugin can pass dependency rules through the build
method,
but it can also define rules through the ExtraParam
extension parameter.
The Required
plugin supports both RequiredExtraParam
and RequiredGroupExtraParam
extension parameter.
The following code is a use of RequiredExtraParam
,
which generates a validation rule for user_name
dependent on email
via extra_param_list=[RequiredExtraParam(main_column="email")
.
Flask Starlette Sanic Tornado
docs_source_code/plugin/param_plugin/flask_with_required_plugin_and_extra_param_demo.py from typing import Optional
from flask import Flask , Response , jsonify
from pait import field
from pait.app.flask import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredExtraParam , RequiredPlugin
def api_exception ( exc : Exception ) -> Response :
if isinstance ( exc , TipException ):
exc = exc . exc
return jsonify ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ RequiredExtraParam ( main_column = "email" )]),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> Response :
return jsonify ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Flask ( "demo" )
app . add_url_rule ( "/api/demo" , view_func = demo , methods = [ "GET" ])
app . errorhandler ( Exception )( api_exception )
if __name__ == "__main__" :
app . run ( port = 8000 )
docs_source_code/plugin/param_plugin/starlette_with_required_plugin_and_extra_param_demo.py from typing import Optional
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from pait import field
from pait.app.starlette import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredExtraParam , RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> JSONResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return JSONResponse ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ RequiredExtraParam ( main_column = "email" )]),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> JSONResponse :
return JSONResponse ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Starlette ( routes = [ Route ( "/api/demo" , demo , methods = [ "GET" ])])
app . add_exception_handler ( Exception , api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/sanic_with_required_plugin_and_extra_param_demo.py from typing import Optional
from sanic import Request , Sanic
from sanic.response import HTTPResponse , json
from pait import field
from pait.app.sanic import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredExtraParam , RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> HTTPResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return json ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ RequiredExtraParam ( main_column = "email" )]),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> HTTPResponse :
return json ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Sanic ( "demo" )
app . add_route ( demo , "/api/demo" , methods = [ "GET" ])
app . exception ( Exception )( api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/tornado_with_required_plugin_and_extra_param_demo.py from typing import Optional
from tornado.ioloop import IOLoop
from tornado.web import Application , RequestHandler
from pait import field
from pait.app.tornado import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredExtraParam , RequiredPlugin
class _Handler ( RequestHandler ):
def _handle_request_exception ( self , exc : BaseException ) -> None :
if isinstance ( exc , TipException ):
exc = exc . exc
self . write ({ "data" : str ( exc )})
self . finish ()
class DemoHandler ( _Handler ):
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def get (
self ,
uid : str = field . Query . i (),
email : Optional [ str ] = field . Query . i ( default = None ),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredExtraParam ( main_column = "email" )]
),
) -> None :
self . write ({ "uid" : uid , "user_name" : user_name , "email" : email })
app : Application = Application ([( r "/api/demo" , DemoHandler )])
if __name__ == "__main__" :
app . listen ( 8000 )
IOLoop . instance () . start ()
Another extension parameter RequiredGroupExtraParam
is to categorize the parameters by group
and mark one of the parameters in this group as the main parameter by is_main
,
so that all other parameters in the group will depend on the main parameter.
The following sample code categorizes user_name
and email
parameters into my-group
,
and defines the email
parameter as the main parameter of my-group
,
so that the generated validation rules depend on the user_name
parameter and the email
parameter.
Flask Starlette Sanic Tornado
docs_source_code/plugin/param_plugin/flask_with_required_plugin_and_group_extra_param_demo.py from typing import Optional
from flask import Flask , Response , jsonify
from pait import field
from pait.app.flask import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredGroupExtraParam , RequiredPlugin
def api_exception ( exc : Exception ) -> Response :
if isinstance ( exc , TipException ):
exc = exc . exc
return jsonify ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" )]
),
email : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" , is_main = True )]
),
) -> Response :
return jsonify ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Flask ( "demo" )
app . add_url_rule ( "/api/demo" , view_func = demo , methods = [ "GET" ])
app . errorhandler ( Exception )( api_exception )
if __name__ == "__main__" :
app . run ( port = 8000 )
docs_source_code/plugin/param_plugin/starlette_with_required_plugin_and_group_extra_param_demo.py from typing import Optional
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from pait import field
from pait.app.starlette import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredGroupExtraParam , RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> JSONResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return JSONResponse ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" )]
),
email : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" , is_main = True )]
),
) -> JSONResponse :
return JSONResponse ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Starlette ( routes = [ Route ( "/api/demo" , demo , methods = [ "GET" ])])
app . add_exception_handler ( Exception , api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/sanic_with_required_plugin_and_group_extra_param_demo.py from typing import Optional
from sanic import Request , Sanic
from sanic.response import HTTPResponse , json
from pait import field
from pait.app.sanic import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredGroupExtraParam , RequiredPlugin
async def api_exception ( request : Request , exc : Exception ) -> HTTPResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return json ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" )]
),
email : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" , is_main = True )]
),
) -> HTTPResponse :
return json ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Sanic ( "demo" )
app . add_route ( demo , "/api/demo" , methods = [ "GET" ])
app . exception ( Exception )( api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/tornado_with_required_plugin_and_group_extra_param_demo.py from typing import Optional
from tornado.ioloop import IOLoop
from tornado.web import Application , RequestHandler
from pait import field
from pait.app.tornado import pait
from pait.exceptions import TipException
from pait.plugin.required import RequiredGroupExtraParam , RequiredPlugin
class _Handler ( RequestHandler ):
def _handle_request_exception ( self , exc : BaseException ) -> None :
if isinstance ( exc , TipException ):
exc = exc . exc
self . write ({ "data" : str ( exc )})
self . finish ()
class DemoHandler ( _Handler ):
@pait ( post_plugin_list = [ RequiredPlugin . build ()])
async def get (
self ,
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" )]
),
email : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ RequiredGroupExtraParam ( group = "my-group" , is_main = True )]
),
) -> None :
self . write ({ "uid" : uid , "user_name" : user_name , "email" : email })
app : Application = Application ([( r "/api/demo" , DemoHandler )])
if __name__ == "__main__" :
app . listen ( 8000 )
IOLoop . instance () . start ()
2.AtMostOneOf Plugin
The main function of the AtMostOneOf
plugin is to verify whether the parameters are mutually exclusive.
for example, if there are three parameters A, B and C and the B parameter is required to be mutually exclusive with the C parameter,
that if B exists, C cannot exist, and if C exists, B cannot exist.
This can use AtMostOneOf
plugin configuration rules to achieve the function, the code is as follows:
Flask Starlette Sanic Tornado
docs_source_code/plugin/param_plugin/flask_with_at_most_one_of_plugin_demo.py from typing import Optional
from flask import Flask , Response , jsonify
from pait import field
from pait.app.flask import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfPlugin
def api_exception ( exc : Exception ) -> Response :
if isinstance ( exc , TipException ):
exc = exc . exc
return jsonify ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ( at_most_one_of_list = [[ "email" , "user_name" ]])])
def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> Response :
return jsonify ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Flask ( "demo" )
app . add_url_rule ( "/api/demo" , view_func = demo , methods = [ "GET" ])
app . errorhandler ( Exception )( api_exception )
if __name__ == "__main__" :
app . run ( port = 8000 )
docs_source_code/plugin/param_plugin/starlette_with_at_most_one_of_plugin_demo.py from typing import Optional
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from pait import field
from pait.app.starlette import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfPlugin
async def api_exception ( request : Request , exc : Exception ) -> JSONResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return JSONResponse ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ( at_most_one_of_list = [[ "email" , "user_name" ]])])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> JSONResponse :
return JSONResponse ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Starlette ( routes = [ Route ( "/api/demo" , demo , methods = [ "GET" ])])
app . add_exception_handler ( Exception , api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/sanic_with_at_most_one_of_plugin_demo.py from typing import Optional
from sanic import Request , Sanic
from sanic.response import HTTPResponse , json
from pait import field
from pait.app.sanic import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfPlugin
async def api_exception ( request : Request , exc : Exception ) -> HTTPResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return json ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ( at_most_one_of_list = [[ "email" , "user_name" ]])])
async def demo (
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> HTTPResponse :
return json ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Sanic ( "demo" )
app . add_route ( demo , "/api/demo" , methods = [ "GET" ])
app . exception ( Exception )( api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/tornado_with_at_most_one_of_plugin_demo.py from typing import Optional
from tornado.ioloop import IOLoop
from tornado.web import Application , RequestHandler
from pait import field
from pait.app.tornado import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfPlugin
class _Handler ( RequestHandler ):
def _handle_request_exception ( self , exc : BaseException ) -> None :
if isinstance ( exc , TipException ):
exc = exc . exc
self . write ({ "data" : str ( exc )})
self . finish ()
class DemoHandler ( _Handler ):
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ( at_most_one_of_list = [[ "email" , "user_name" ]])])
async def get (
self ,
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i ( default = None ),
email : Optional [ str ] = field . Query . i ( default = None ),
) -> None :
self . write ({ "uid" : uid , "user_name" : user_name , "email" : email })
app : Application = Application ([( r "/api/demo" , DemoHandler )])
if __name__ == "__main__" :
app . listen ( 8000 )
IOLoop . instance () . start ()
In the sample code, uid
is a required parameter, while user_name
and email
are optional parameters,
and after using the AtMostOneOfPlugin
plugin a new validation rule will be added.
This validation rule is defined by the parameter at_most_one_of_list
,
which indicates that the parameters email
and user_name
cannot exist at the same time.
After sending a request using curl
, the response shows that an error is returned when both email
and user_name
are present,
but otherwise the response is returned normally.
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123
{ "uid" :"123" ,"user_name" :null,"email" :null} %
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123 \& email\= aaa
{ "uid" :"123" ,"user_name" :null,"email" :"aaa" } %
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123 \& user_name\= so1n
{ "uid" :"123" ,"user_name" :"so1n" ,"email" :null} %
➜ ~ curl http://127.0.0.1:8000/api/demo\? uid\= 123 \& email\= aaa\& user_name\= so1n
{ "data" :"requires at most one of param email or user_name" } %
In addition, the AtMostOneOf
plugin also supports grouping parameters by ExtraParam
and restricting them to not appearing at the same time,
using the following method:
Flask Starlette Sanic Tornado
docs_source_code/plugin/param_plugin/flask_with_at_most_one_of_plugin_and_extra_param_demo.py from typing import Optional
from flask import Flask , Response , jsonify
from pait import field
from pait.app.flask import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfExtraParam , AtMostOneOfPlugin
def api_exception ( exc : Exception ) -> Response :
if isinstance ( exc , TipException ):
exc = exc . exc
return jsonify ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ()])
def demo (
uid : str = field . Query . i (),
email : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
) -> Response :
return jsonify ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Flask ( "demo" )
app . add_url_rule ( "/api/demo" , view_func = demo , methods = [ "GET" ])
app . errorhandler ( Exception )( api_exception )
if __name__ == "__main__" :
app . run ( port = 8000 )
docs_source_code/plugin/param_plugin/starlette_with_at_most_one_of_plugin_and_extra_param_demo.py from typing import Optional
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from pait import field
from pait.app.starlette import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfExtraParam , AtMostOneOfPlugin
async def api_exception ( request : Request , exc : Exception ) -> JSONResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return JSONResponse ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
email : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
) -> JSONResponse :
return JSONResponse ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Starlette ( routes = [ Route ( "/api/demo" , demo , methods = [ "GET" ])])
app . add_exception_handler ( Exception , api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/sanic_with_at_most_one_of_plugin_and_extra_param_demo.py from typing import Optional
from sanic import Request , Sanic
from sanic.response import HTTPResponse , json
from pait import field
from pait.app.sanic import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfExtraParam , AtMostOneOfPlugin
async def api_exception ( request : Request , exc : Exception ) -> HTTPResponse :
if isinstance ( exc , TipException ):
exc = exc . exc
return json ({ "data" : str ( exc )})
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ()])
async def demo (
uid : str = field . Query . i (),
email : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
user_name : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
) -> HTTPResponse :
return json ({ "uid" : uid , "user_name" : user_name , "email" : email })
app = Sanic ( "demo" )
app . add_route ( demo , "/api/demo" , methods = [ "GET" ])
app . exception ( Exception )( api_exception )
if __name__ == "__main__" :
import uvicorn
uvicorn . run ( app )
docs_source_code/plugin/param_plugin/tornado_with_at_most_one_of_plugin_and_extra_param_demo.py from typing import Optional
from tornado.ioloop import IOLoop
from tornado.web import Application , RequestHandler
from pait import field
from pait.app.tornado import pait
from pait.exceptions import TipException
from pait.plugin.at_most_one_of import AtMostOneOfExtraParam , AtMostOneOfPlugin
class _Handler ( RequestHandler ):
def _handle_request_exception ( self , exc : BaseException ) -> None :
if isinstance ( exc , TipException ):
exc = exc . exc
self . write ( str ( exc ))
self . finish ()
class DemoHandler ( _Handler ):
@pait ( post_plugin_list = [ AtMostOneOfPlugin . build ()])
async def get (
self ,
uid : str = field . Query . i (),
user_name : Optional [ str ] = field . Query . i (
default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]
),
email : Optional [ str ] = field . Query . i ( default = None , extra_param_list = [ AtMostOneOfExtraParam ( group = "my-group" )]),
) -> None :
self . write ({ "uid" : uid , "user_name" : user_name , "email" : email })
app : Application = Application ([( r "/api/demo" , DemoHandler )])
if __name__ == "__main__" :
app . listen ( 8000 )
IOLoop . instance () . start ()
In this code, the user_name
and email
parameters are grouped into my-group
using AtMostOneOfExtraParam
.
At runtime, the AtMostOneOf
plugin verifies that both the user_name
and email
parameters exist,
and throws an error if both exist.