Pait in addition to parameter type conversion and checking,
but also supports the automatic generation of route function OpenAPI data.
You only need to write the code of the route function,
Pait can generate the corresponding OpenAPI documentation of the route function,
such as Documentation Home of the sample code:
As you can see through the page, the data displayed on the Swagger page includes the data of the response object, the data labeled by the Pait decorator, and the parameters of the route function.
2.OpenAPI properties of route functions
Binding OpenAPI attributes to a route function is very simple,
just need to fill in the Pait decorator with the corresponding attributes.
Common route function attribute bindings are in the following code:
frompait.app.anyimportpaitfrompait.model.tagimportTagdemo_tag=Tag("demo tag",desc="demo tag desc")@pait(desc="demo func desc",name="demo",summary="demo func summary",tag=(demo_tag,))defdemo()->None:pass
The OpenAPI information for the route function is specified through the Pait attributes, which do the following:
Attributes
OpenAPI Attributes
Description
desc
description
Documentation of the interface in detail
name
operation_id
The name of the interface
summary
summary
Brief description of the interface
tag
tag
The OpenAPI tag of the interface
Note
1.In most cases, the name attribute is just part of the operation_id attribute and Pait does not guarantee that name is exactly equal to operation_id.
2.Tag should be guaranteed to be globally unique
However, the name and desc attributes can also be obtained from the route function name and the __doc__ of the route function
For example, the name and desc attributes of the route function in the following code are consistent with the code above:
frompait.app.anyimportpaitfrompait.model.tagimportTagdemo_tag=Tag("demo tag",desc="demo tag desc")@pait(summary="demo func summary",tag=(demo_tag,))defdemo()->None:"""demo func desc"""pass
In addition to the above attributes, OpenAPI has an attribute called deprecated,
which is primarily used to mark whether an interface has been deprecated.
Pait does not directly support the marking of the deprecated attribute,
but instead determines whether the deprecated of a route function is True by using PaitStatus,
which is very simple to use, as in the following code:
This code indicates that the route function is under test and deprecated is False,
for more statuses and whether it is deprecated or not see the following table.
status value
stage
deprecated
description
undefined
default
False
undefined, default status
design
development
False
design
dev
development
False
development and testing
integration_testing
development
False
integration testing
complete
development complete
False
development complete
test
development complete
False
testing
pre_release
release
False
pre release
release
release
False
release
abnormal
offline
True
Temporary offline
maintenance
offline
False
Maintenance
archive
offline
True
archive
abandoned
offline
True
abandoned, will not be used again
3.The response object of the route function
In the previous introduction, a list of response objects for a route function is defined via response_model_list,
which contains one or more response objects.
Note
It is recommended to use only one response object,
if there is more than one, most non-OpenAPI feature(e.g. plugins) will default to using only the first response object.
Pait provides a variety of response objects, as listed below:
Response Object Name
Description
JsonResponseModel
Object whose response is Json
XmlResponseModel
Object whose response is Xml
TextResponseModel
Objects whose response is text
HtmlResponseModel
Objects whose response is Html
FileResponseModel
Objects whose response is File
Pait only provides response objects for common response types, if there is no applicable response object,
can define a response object that meets the requirements through pait.model.response.BaseResponseModel.
which is a container for the different properties of the OpenAPI response object, as follows.
Attribute Name
Description
response_data
Define the response data, if it is response data with a structure then it should be a pydantic.BaseModel describing the structure
media_type
The Media Type of the response object
name
The name of the response object.
description
The description of the response object
header
The header of the response object, the value should be pydantic.BaseModel not Dict
status_code
The Http status code of the response object, defaults to (200, )
The first highlighted code is a response object which indicates that the Http status codes may be 200, 201 and 404.
The Media Type is application/json.
The Header has properties X-Token and Content-Type.
And most importantly, the data structure of the response body is defined as follows:
The second highlighted code binds the response object to the route function.
Now run the code and visit 127.0.0.1:8000/redoc in your browser,
you can see that the current page displays the OpenAPI data of the route function in full, as follows
Note
Since Redoc presents data in a much more parsimonious way than Swagger, this case uses Redoc to present data.
In fact Pait supports a variety of OpenAPI UI pages, see OpenAPI routes for details:.
4.Field
The page in the previous section contains not only the data of the response object,
but also the data of the request parameters.
such as the uid parameter, which is declared as required and is also declared to be of type integer with a value in the range of 10-1000.
These request parameters are declared through Field objects,
which not only validate the parameters but also provide data for OpenAPI.
In addition to this, the Field object has some properties that are specialized for OpenAPI, they include:
Attributes
description
links
OpenAPI link function, used to specify parameters associated with a response object
media_type
Defines the Media Type of a parameter, currently only Body, Json, File, Form, MultiForm are used, it is recommended to use only one Media Type for an route function.
openapi_serialization
Define the serialization of the parameters, please refer to serialization
example
Define an example value for the parameter; Pait supports factory functions, but converting to OpenAPI will result in a fixed value generated in the moment
openapi_include
If the value is False, Pait will not consider this parameter when generating the Open API
4.1.Links
Links is a feature of OpenAPI that is used to specify that a request parameter from interface A is associated with a piece of data in the response object from interface B. For example:
importhashlibfromtypingimportTypefrompydanticimportBaseModel,Fieldfromtornado.ioloopimportIOLoopfromtornado.webimportApplication,RequestHandlerfrompaitimportfieldfrompait.app.tornadoimportpaitfrompait.model.responseimportJsonResponseModelfrompait.openapi.doc_routeimportAddDocRoutefrompait.openapi.openapiimportLinksModelclassLoginRespModel(JsonResponseModel):classResponseModel(BaseModel):# type: ignoreclassDataModel(BaseModel):token:strcode:int=Field(0,description="api code")msg:str=Field("success",description="api status msg")data:DataModeldescription:str="login response"response_data:Type[BaseModel]=ResponseModellink_login_token_model:LinksModel=LinksModel(LoginRespModel,"$response.body#/data/token",desc="test links model")classLoginHandler(RequestHandler):@pait(response_model_list=[LoginRespModel])asyncdefpost(self,uid:str=field.Json.i(description="user id"),password:str=field.Json.i(description="password"))->None:self.write({"code":0,"msg":"","data":{"token":hashlib.sha256((uid+password).encode("utf-8")).hexdigest()}})classGetUserHandler(RequestHandler):@pait()defget(self,token:str=field.Header.i("",description="token",links=link_login_token_model,),)->None:iftoken:self.write({"code":0,"msg":""})else:self.write({"code":1,"msg":""})app:Application=Application([(r"/api/login",LoginHandler),(r"/api/get-user-info",GetUserHandler)],)AddDocRoute(app)if__name__=="__main__":app.listen(8000)IOLoop.instance().start()
This example defines a login route function--login_route and a route function to get user details -- get_user_route.
The route function to get the user details needs a token parameter to verify the user and get the user id,
which is generated by the login route function,
so the token parameter of the user details route function is related to the token in the response data of the login route function.
In order for OpenAPI to recognize that the token parameter is associated with a token in the response object.
First create an instance named link_login_token_model that is bound to the LoginRespModel response object and indicates the parameter to be bound by the expression $response.body#/data/token".
Then the link_login_token_model is assigned to the links attribute of the Field of the token in the get_user_route route function, and this completes the association once.
After running the code and visiting http://127.0.0.1:8000/swagger in your browser you will see the following page:
can see through the page that the Response column of the login interface shows the Links data on the far right.
Note
Currently, many OpenAPI tools only provide simple Links support. For more information on the use and description of Links, see Swagger Links.
5.OpenAPI generation
In the OpenAPI ecosystem, at its core is a piece of OpenAPI-conforming json or yaml text,
which can be used in OpenAPI pages such as Swagger, or imported for use in tools such as Postman.
Pait will delegate the collected data to AnyAPI to be processed and generate an OpenAPI object, which supports being converted into a variety of human-readable text or pages.
Note
AnyAPI is separated from Pait and is currently for Pait use only, more features will be added to AnyAPI in subsequent releases.
The following is an example of generating an OpenAPI object and generating output content based on the OpenAPI object:
The first step in the sample code is to create openapi_model,
which in the process of creation will get the app corresponding interface and data.
The second step is to call the content method of openapi_model, which has a serialization_callback parameter with a default value of json.dump.
So a direct call to openapi_model.content() will generate the following JSON text.
Json example (the example text is long, please open it as needed)
In addition, the sample code also customizes a function that serializes to yaml -- my_serialization and generates the following yaml text via openapi_model.content(serialization_callback=my_serialization):
Yaml example (the example text is long, please open it as needed)