Request and response of flask introductory tutorial

Flask is a lightweight web development framework that relies on jinja2 and a micro-framework of Werkzeug WSGI services.
Official document: https://flask.palletsprojects.com/en/2.0.x/
Chinese document: http://docs.jinkan.org/docs/flask/
The version of Chinese document will be relatively low, if English is OK, you can See the official documentation.

Installation & Getting Started Examples

Install using the pip command:pip install flask

Create a new py script, here is the flask_hello.py script, the content of the script is as follows:

from flask import Flask
app =  Flask(__name__)

@app.route("/")
def hello_world():
    return "<h1>Hello World!</h1>"

In the script, you need to import the Flask class, create the Flask object app, and then use the app.route() decorator to set the route (that is, the interface path) of hello_world().
After the script is edited, start the flask service of the script, switch to the directory where the script is located, and execute the flask run command: flask --app flask_hello run(flask_hello is the script name)
insert image description here
insert image description here

The command to start the flask service is different for different flask versions. I am using version 2.2.2 here. If you want to know other versions, you can go to the official website to select the corresponding version to view
insert image description here

Another way to start the flask service is to write the startup code in the script:

from flask import Flask
app =  Flask(__name__)

@app.route("/")
def hello_world():
    return "<h1>Hello World!</h1>--python命令启动"

if __name__=="__main__":
	# 启动flask服务
    app.run()

The python command executes the script, and the results are as follows:
insert image description here
insert image description here

routing

When we access the http or https link (ie url), there is an interface path. In the flask service, we can determine which program handles the request according to the interface path. Routing includes static routing and dynamic routing. route(rule: str, **options: t.Any)The way to set the route is to define a Flask object first, and then route according to the definition in the Flask object

static route

Static routing means that the path is fixed and does not change. For example, in the example of getting started, @app.route("/")it is the static root route.
The example is as follows:
The content of the py script is defined as follows:

from flask import Flask

app = Flask(__name__)

@app.route("/search/video")
def search_videos():
    return "查找视频资源"

@app.route("/search/picture")
def search_pictures():
    return "查找图片资源"

if __name__=="__main__":
    app.run()

Among them, /search/videoand /search/pictureare defined static routes, and the interface path during access does not change
insert image description here

dynamic routing

Sometimes, the interface path changes, such as querying user information, querying user A, user B, and user C, and the user information is uncontrollable. It is impossible to create a route for each user. Flask provides dynamic routing to define the changed information as a variable.
When adding a route, use the definition for the changed part <变量名>, and then decorate the function or method. The name of the parameter is the same as the defined variable name, so that the function or method can use the variable and its value.
Example:

from flask import Flask

app = Flask(__name__)

@app.route("/userinfo/<user_id>/info")
def search_videos(user_id):
    return f"这个是{
      
      user_id}的用户信息"

if __name__=="__main__":
    app.run()

Execute the script, start the flask service, and visit as follows:
insert image description here
From the results, it can be seen that the content of /userinfo/after/before info can be changed, and it can also be processed successfully.

Limited type

In dynamic routing, you can limit the data type of the variable, the format: <类型:变量名>
the data type is as follows:

type describe
string (default) accepts any text that does not contain a slash
int Accepts positive integers
float Accepts positive floating point numbers
path Like string, but can contain slashes
uuid Accepts UUID strings

Example:

from flask import Flask

app = Flask(__name__)

@app.route("/userinfo/<int:user_id>/info")
def search_videos(user_id):
    return f"用户编号{
      
      user_id}的信息如下:巴拉巴拉巴拉。。。"

if __name__=="__main__":
    app.run()

After the script is executed, the flask service starts and the access is as follows:
insert image description here

The data type restriction of variables in dynamic routing is relatively simple. If it is complex verification, it can be verified inside the function.

end of address/

Sometimes when we add /or not add at the end of the interface path /, the access is consistent, but some add access and report an error, flask has to deal /with the end of the route :/

  • The tail of the route added by flask has : the effect of adding and not adding /the access is the same//
  • There is no tail of the route added by flask /: when access is added, /an error will be reported, and /the access can only be successful if it is not added.

Examples are as follows:

from flask import Flask

app = Flask(__name__)

@app.route("/add1/")
def add1():
    return f"路由的末尾有'/'"

@app.route("/add2")
def add2():
    return f"路由的末尾没有'/'"

if __name__=="__main__":
    app.run()

After starting the flask service, the execution results are as follows:
insert image description here

Request method settings

The request methods include GET, POST, PUT, etc., and the commonly used ones are GET and POST. We can pass in methodsparameters when setting the route of the Flask() object to set the request method of the route. Format: @Flask().route(rule, methods=["GET", xxx, xxx])
The content of the script is as follows:

from flask import Flask

app = Flask(__name__)

@app.route("/get_demo/info", methods=["GET"])
def only_get():
    return "只支持get请求方式"

@app.route("/post_and_get_demo/info", methods=["GET", "POST"])
def both_post_get():
    return "支持get和post的请求方式"

if __name__=="__main__":
    app.run()

After starting the corresponding flask service, the interface access is as follows:
insert image description here

request data processing

When sending a request, the uploaded parameters must be touched, and then logically processed according to the uploaded parameters. So how do we get the data uploaded by the request? The flask framework provides the request class, through which the corresponding request data can be obtained.

properties/methods illustrate
args Records the query parameters in the request and returns dictionary-like data
json Record the json data in the request (dict type)
files Records the requested uploaded files and returns dictionary-like data
form Records the form data in the request and returns dictionary-like data
method Records the HTTP method used by the request
url The URL address in the request is recorded
host The requested domain name is logged
headers The request header information of the request is recorded, and data similar to a dictionary is returned

Example:

from flask import Flask, request

wen = Flask(__name__)

@wen.route("/request/info", methods=["GET"])
def get_request_info():
    print(f"request.args类型:{
      
      type(request.args)}")
    print(f"request.args = {
      
      request.args}\n")

    print(f"request.json类型:{
      
      type(request.json)}")
    print(f"request.json = {
      
      request.json}\n")

    print(f"request.files类型:{
      
      type(request.files)}")
    print(f"request.files = {
      
      request.files}\n")

    print(f"request.form类型:{
      
      type(request.form)}")
    print(f"request.form = {
      
      request.form}\n")

    print(f"request.method类型:{
      
      type(request.method)}")
    print(f"request.method = {
      
      request.method}\n")

    print(f"request.url类型:{
      
      type(request.url)}")
    print(f"request.url = {
      
      request.url}\n")

    print(f"request.host类型:{
      
      type(request.host)}")
    print(f"request.host = {
      
      request.host}\n")

    print(f"request.headers类型:{
      
      type(request.headers)}")
    print(f"request.headers = {
      
      request.headers}\n")

    return {
    
    "status": 0, "message": "get success"}

if __name__ == "__main__":
    wen.run()

Execute the python script (that is, start the flask service) and send the request.
insert image description here
The console output is as follows:
insert image description here

Request parameter processing

In the url link, sometimes there are request parameters, we can get the request parameters through the args attribute under flask.request
Example:

from flask import Flask, request

wen = Flask(__name__)

@wen.route("/get/info", methods=["GET", "POST"])
def get_request_info():
    data = {
    
    }
    data.update(request.args)
    print(data)
    return data

if __name__ == "__main__":
    wen.run()

After starting the flask service, send a request and view the response message:
insert image description here
insert image description here

Request body json data processing

When sending a request, sometimes the request body data is json data, and flask can get the json request body data through the json attribute under flask.request. The script
content is as follows:

from flask import Flask, request

app = Flask(__name__)

@app.route("/post/info", methods=[ "POST"])
def post_json_data():
    print(f"请求json报文:{
      
      request.json}")
    return {
    
    "code": 0, "body_data": request.json}

if __name__ == "__main__":
    app.run()

After starting the flask service, send a post request, the result is as follows:
insert image description here
insert image description here

Form request data processing

When sending a request, sometimes the request body data is json data, and flask can get the form form data through the form attribute under flask.request. The script
content is as follows:

from flask import Flask, request

app = Flask(__name__)

@app.route("/form/info", methods=[ "POST"])
def post_form_data():
    print(f"form数据:{
      
      request.form}")
    return {
    
    "code": 0, "form_data": request.form}

if __name__ == "__main__":
    app.run()

Execute the script, start the flask service, and send a request. The related results are as follows:
insert image description here
insert image description here

file request data processing

Some requests are to upload files, and flask can obtain the uploaded file data through the files attribute under flask.request.

  • request.files: Returns data similar to a dictionary type, including all uploaded file objects FileStorage, and specific file objects can be obtained through get("xxx"), such as the file object indicating that the acquisition parameter request.files.get("data")is data

The file object FileStorage has multiple methods to support operations, the commonly used ones are:

properties/methods illustrate
filename file name
stream file stream object
save(dst, buffer_size=16384) Save the contents of the file object to the specified path dst

The script content is as follows:

from flask import Flask, request

app = Flask(__name__)

@app.route("/form/info", methods=[ "POST"])
def post_form_data():
    print(f"files数据:{
      
      request.files}")
    fo = request.files.get("data")
    for data in fo.stream:
        print(data.decode("utf-8"), end="")
    return {
    
    "code": 0, "file_name": fo.filename}

if __name__ == "__main__":
    app.run()

Execute the script (start the flask service) and send a request for file upload.
insert image description here
The console output is:
insert image description here

Response data settings

The returned response message has multiple formats, such as text, json, html, etc.

return text

If the response message is text content, return the string content directly in the function, and flask will encapsulate it into a text format response message.
Example:

from flask import Flask

app = Flask(__name__)

@app.route("/text", methods=[ "POST"])
def text_resp():
    return "响应报文内容是文本内容"

if __name__ == "__main__":
    app.run()

After executing the script, postman sends the request as follows:
insert image description here
From the response message, we can see that the Content-Type of the response header is text/html, and the response message body is a text content

Set status code and request header

In addition to setting the response message, we can also return a tuple. The tuple must contain the message body, and can contain the response status code and response header. The returned tuple is set as follows:

  • (response, status)
  • (response, headers)
  • (response, status, headers)

The response status code status defaults to 200, and the headers will be simply adjusted according to the response.
Example:

from flask import Flask

app = Flask(__name__)

@app.route("/demo1", methods=[ "POST"])
def response_status():
    return "响应报文内容是文本内容", 201

@app.route("/demo2", methods=[ "POST"])
def resp_json_status():
    return {
    
    "name": "wenxiaoba", "age": 18}, 201

@app.route("/demo3", methods=[ "POST"])
def resp_headers():
    return "设置了响应报文和响应头", {
    
    "token": "123456abcde", "address": "where are you"}

@app.route("/demo4", methods=[ "POST"])
def resp_status_headers():
    return "设置了响应报文和响应头", 202, {
    
    "token": "123456abcde", "address": "where are you"}

if __name__ == "__main__":
    app.run()

Execute the script (start the flask service) and send the request. The relevant content is as follows:
When requesting /demo1, you can see the response message body and response status code are the set content.
insert image description here
When requesting /demo2, the response message body is in json format.
insert image description here
insert image description here
When requesting /demo3 , returns the set response message body, the response status code is flask’s default 200, and the response header also contains the set field
insert image description here
insert image description here
request/demo4, the returned response message body and status code are both set, and the response header also contains the set field
insert image description here
insert image description here

return json

The response data returned by most interfaces is in json format. In the flask framework, there are two ways to return the response message in json format:

  • Return dict directly: the bottom layer of flask will convert dict into json format
  • Use the jsonify() method to pass in key-value pairs or dictionaries to return json data through parameters, and you need to import flask.jsonify

When returning dict (dictionary) data, the client actually receives json data
insert image description here
/jsonify1 interface is the response message processed by passing in dictionary parameters through jsonify()
insert image description here
/jsonify2 interface is passed in key-value pair parameter processing through jsonify() The response message of
insert image description here

return other formats

In addition to the commonly used json and text formats, other formats will be returned, such as html, xml, etc. We can use the render_template() function for processing.
To use the render_template() function, you need to import flask.render_template first. The function is as follows:
render_template(template_name_or_list, **context)

  • template_name_or_list: Generally, the name of the incoming template, the template must be stored in the same templatesdirectory as the script
  • context: context, there are some variables to be replaced in the general template (the format is: { {变量名}}), which can be passed in through this parameter, and the key-value pair is passed in, such as: variable name=value

The content of the py script is as follows:

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/gethtml", methods=["POST"])
def get_html():
    return render_template('demo.html', name="wenxiaoba")

@app.route("/getxml", methods=["POST"])
def get_xml():
	# 由于返回的是xml数据,所以需要设置响应头的content-type内容,说明传输的是xml数据,否则会被当成html数据
    return render_template('data.xml', book_name="随便起的书名"), {
    
    "content-type": "application/xml"}

if __name__ == "__main__":
    app.run()

In the same directory as the script, create a templates directory, and create demo.html and data.xml files in the templates directory.
The content of demo.html is as follows:

<html>
    <body>
        <h1>{
   
   {name}}的博客</h1>
        <p>这是一个非常勤奋的娃,她想做测试开发,赚更多的钱</p>
    </body>
</html>

The content of data.xml is as follows:

<book>
    <body>
        <book_name>python简明教程</book_name>
        <author>谁谁谁</author>
        <price>56</price>
    </body>
    <body>
        <book_name>{
   
   {book_name}}</book_name>
        <author>不知道</author>
        <price>62.3</price>
    </body>
</book>

Execute the py script (start the flask service), send the request, and the results are as follows:
insert image description here
insert image description here

Set additional data - make_response()

If you want to set more response information, such as cookies, you can get make_response()a response object, and you can set cookies, request headers, etc. in this object.
Example:
The content of the py script is as follows:

from flask import Flask, request, make_response, render_template

app = Flask(__name__)

@app.route("/setcookie", methods=["POST"])
def set_cookie():
    type = request.json.get("type")
    if "html" == type:	# 如果请求上传的json中,type为html时,返回html内容
        resp = make_response(render_template("demo.html", name="wenxiaoba"))
    else:
        dict_data = {
    
    
            "name": "wenxiaoba",
            "age": 32,
            "gender": True
        }
        resp = make_response(dict_data)
    # 设置cookie,
    resp.set_cookie("cookie1", "cookie1_value")
    resp.set_cookie("cookie2", "cookie2 value")
    # 设置响应头
    resp.headers["test"] = "test headers value"
    return resp

if __name__ == "__main__":
    app.run()

After the script is executed (that is, the flask service is started), the request is sent, and the results are as follows:
insert image description here
insert image description here

Start service configuration

In the previous example, we basically started the flask service by executing the run() method through the script. The run() method can pass in multiple parameters to configure the service content, but we have not set any parameters. Now let’s compare Common parameters.
run() method:run(host, port, debug, load_dotenv=True, **options)

  • host: 127.0.0.1 is started by default, which can only be accessed locally, and 0.0.0.0 can only be accessed by LAN. If you want normal access from the public network, deploy the flask service to the public network server and pass in the server ip as the host parameter
  • port: Listening port number, the default is 5000, int data type, other port numbers can be passed in
  • debug: Whether to enable the debug mode, the default is False (i.e. production), if it is True, it will monitor whether the script is saved, if there is a save operation, restart the flask service according to the latest saved script

Example:
The content of the py script is:

from flask import Flask

app = Flask(__name__)

@app.route("/demo", methods=["POST"])
def demo():
    return "content data text"

if __name__ == "__main__":
    app.run(host="192.168.1.105", port=8888, debug=True)

After executing the script (that is, starting the flask service), you can see from the console log that the current flask service is listening on port 8888 of 192.168.1.105 (of course the flask service is also deployed on the 192.168.1.105 device), and it also prompts Debugger The mode is in effect.
insert image description here
We send a request to port 8888.
insert image description here
When we modify the py script and save it, we can see that the console reloads the flask service when we save it. This is the advantage of the debug mode. After the script is edited, there is no need to manually reload it. Start flask, just save and the flask service will be reloaded.
insert image description here
insert image description here

RESTFul style specification

The flask-restx plugin is simple to use

The specification used by the general interface is the RESTFul style specification (I am not sure), flask-restx is a flask plug-in that supports RESTFul, used to standardize the writing of the interface, and supports the official description of the swagger document:
https://github.com/ python-restx/flask-restx
official documentation: https://flask-restx.readthedocs.io/en/latest/
Installation:pip install flask-restx

easy entry

Let's get started with the official example. The official script is as follows:

from flask import Flask
from flask_restx import Resource, Api

# 创建Flask对象app
app = Flask(__name__)
# 创建Api对象api,创建时,将Flask对象app作为参数传入
api = Api(app)

# 使用Api对象api来添加路由(不使用Flask对象app来添加路由)
# 至于methods,不在添加路由时限制,在装饰的类方法中限制
@api.route('/hello')
class HelloWorld(Resource):     # 创建HelloWorld类,必须继承Resource模块
    def get(self):  # 定义RESTFul风格的get方法(对应get请求方式)
        return {
    
    'hello': 'world'}

if __name__ == '__main__':
    app.run(debug=True)

Execute the script (start the flask service), send the request, and the result is as follows:
insert image description here
According to the comments in the example, if we want to define an interface that supports get and post request methods, we need to define get() and post() in the corresponding class method, a simple example is as follows:
The content of the py script is as follows:

from flask import Flask, request
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)

@api.route("/person/info")
class Person(Resource):
    def get(self):
        return "get方法不安全,没有权限查看个人信息"

    def post(self):
        name = request.json.get("name")
        return {
    
    "name": name, "age": 27, "gender": True}

if __name__=="__main__":
    app.run()

After executing the py script (starting the flask service), the request is sent, and the result is as follows:
get request:
insert image description here
post request:
insert image description here
if the request method is not get or post, an error will be reported
insert image description here

add route

From the example of Simple Getting Started , we know how to add routes. In fact, the flask_restx plugin also provides the add_resource() method to add routes. That is, the flask_restx plugin has 2 methods to add routes:

  • The route() decorator adds routes
  • The add_resource() method adds routes

The route() decorator adds routes

route() can add multiple routes at one time, the example is as follows:
The content of the py script is as follows:

from flask import Flask, request
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)

@api.route("/path1/demo", "/path2/demo", "/path3/demo")
class demo(Resource):
    def post(self):
        return f"接口路径是:{
      
      request.path}"

if __name__=="__main__":
    app.run()

Execute the script (start the flask service), send the request, and the results are as follows:
insert image description here

The add_resource() method adds routes

add_resource() is to add a route to the specified class, the example is as follows:
The content of the py script is as follows:

from flask import Flask, request
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)

class Demo(Resource):
    def post(self, name):
        return {
    
    "path": request.path, "name": name}
# 给Demo类添加路由
api.add_resource(Demo, '/demo1/<name>', '/demo2/<name>/info')

if __name__=="__main__":
    app.run()

Execute the script (start the flask service), send the request, and the results are as follows:
insert image description here

Writing RESTFul-style interfaces

When designing the framework, it is generally followed 复用性、高内聚、低耦合, that is, easy to maintain and reduce redundancy.
High coupling: It can be understood that the program is very complex and difficult to maintain. If a certain part of the program is modified, all aspects (other functions) must be modified accordingly. For example, a program has 100 functions that execute normally, but one of them is modified function, the other 99 functions must be modified accordingly, which is a highly coupled scenario. Low coupling requires splitting the complete process into several independent modules and independent functions. Modifications within modules do not affect the interaction logic between modules. For example, merchant order management and user order payment are different modules, and merchants have been modified. After a certain function of order management, most functions of user order payment do not need to be modified.

Highly coupled example

from flask import Flask, request

app = Flask(__name__)
@app.route("/demo", methods=["GET", "POST", "PUT", "DELETE"])
def demo():
    if request.method == "GET":
        return "获取订单"
    elif request.method == "POST":
        return "生成订单"
    elif request.method == "PUT":
        return "修改订单"
    else:
        return "删除订单"

In this example, the addition, deletion, modification and query of orders are all completed in one function. If you suddenly need to add the function of approving orders one day, other order functions will be affected, you need to read a lot of code, and then add code, and then It is to modify the code, all under one function, which is very unsightly (when you see so many codes, you will feel discouraged), and it is not easy to maintain.

Low cohesion example

from flask import Flask

app = Flask(__name__)

@app.route("/order", methods=["GET"])
def query_order():
    return "查询订单"

@app.route("/order", methods=["POST"])
def create_order():
    return "生成订单"

@app.route("/order", methods=["PUT"])
def modify_order():
    return "修改订单"

@app.route("/order", methods=["DELETE"])
def delete_order():
    return "删除订单"

@app.route("/approval", methods=["POST"])
def approvaled():
    return "审批通过"

@app.route("/approval", methods=["DELETE"])
def reject():
    return "审批驳回"

In this example, there are different request methods for the /order interface and different request methods for the /approval interface. In short, one interface path corresponds to multiple request methods. In this example, the code has no reusability and is rather complicated to maintain. It includes the order management of the operator (addition, deletion, modification and query), and the order management of the approver (approval, approval and rejection). In summary, it can be divided into 2 Dimensions: operator's order management, order approval process. If a module has many functions and dimensions, the maintenance cost will gradually increase, and it is not easy to distinguish. You need to look at the comments or code to determine the processing content of the current function.

RESTFul style example

It needs to be followed during the design process 复用性、高内聚、低耦合. The RESTFul style specification will design different logic according to the request method.

request method illustrate
GET Get server resources
POST Add server resources
PUT Update server resource (client provides complete resource after change)
DELETE delete server resources

Example:

from flask import Flask
from flask_restx import Api, Resource

app = Flask(__name__)
api = Api(app)

@api.route("/order")
class OrderOpt(Resource):
    def get(self):
        return "查询订单"

    def post(self):
        return "生成订单"

    def put(self):
        return "修改订单"

    def delete(self):
        return "删除订单"

@api.route("/approval")
class ApprovalProcess(Resource):
    def post(self):
        return "审批通过"

    def delete(self):
        return "审批驳回"

In this example, the order function is maintained from two dimensions: the order management of the operator and the approval process of the order. Although there may be an impact between the order management and the approval process, the high coupling is reduced to a certain extent, and the other It is also better for maintenance and management.

The flask-restx plugin integrates swagger

Generally speaking, when developing an interface, it needs to provide interface documents to other developers for joint debugging, or to test for interface testing. The flask-restx plug-in integrates swagger, which can manage the module of the interface and configure the interface document.
The flask-restx plugin integrates swagger and depends on the use of namespace.

Use of namespace

In the example of RESTFul style example , if we access the root path of the interface, we find that the interface is as follows: As
insert image description here
can be seen from the figure, the interfaces are all under the default namespace. If there are many interfaces, it is not conducive to management. The namespace of the flask-restx plug-in can be Manage interfaces by category.
To use namespace for interface classification management, the following steps are required:

  • Step 1: Define the Namespace object
  • Step 2: Add a decorator to the class: the route() method of the Namespace object
  • Step 3: Add the access path of the Namespace object to the Api object

The classes or methods used are described as follows:

Namespace class:

  • Define the object:Namespace(name, description=None, path=None, decorators=None, validate=None, authorizations=None, ordered=False, **kwargs)
  • Parameter Description:
    • name: category name
    • description: category description
    • path: pre-path (the complete path of the interface will be determined later based on the decorator in step 2 and the path setting in step 3)

@Namespace().route("") is to classify the class into a certain Namespace object, that is, to classify the interface corresponding to the class into a certain level, and route() can set sub-routes, which are subject to the path parameter and Influenced by the add_namespace() method of step 3,如果不设置子路由,则传入空字符串(不要什么都不传)

The Api object add_namespace(ns, path=None)is to add the corresponding Namespace object ns to the flask service (if it is not added, the interface of the corresponding class will not be recognized), and set the front path path.

Regarding the interface classification management of the namespace, we can see from step 1 to step 3 that there are three places to set the route, namely the parameter path when the Namespace is instantiated, the route() method of the decorator Namespace object, and the add_namespace( ) method, the final result of the interface path of the corresponding interface in these three places is as follows:

  • If the path parameter in the add_namespace() method of the Api object is passed in, the value of the path parameter is used as the pre-path
  • If the path parameter in the add_namespace() method of the Api object is not passed in
    • If the parameter path is passed in when the Namespace is instantiated, the path value will be used as the pre-path
    • If the parameter path is not passed in when the Namespace is instantiated, it defaults to the category name when the Namespace is instantiated as the pre-path
  • The complete path of the interface is: pre-path + parameter value passed in by the route() method

Example:
The content of the py script is as follows:

from flask import Flask
from flask_restx import Api, Resource, Namespace

app = Flask(__name__)
api = Api(app)

# 定义Namespace实例
ns1 = Namespace("demo management", "add_namespace()和Namespace()都有path参数传入", path="/name1")
ns2 = Namespace("demo2 management", "add_namespace()无path参数传入,Namespace()有path参数传入", path="/name2")
ns3 = Namespace("demo3 management", "add_namespace()和Namespace()都无path参数传入")
ns4 = Namespace("demo4 management", "add_namespace()和Namespace()都有path参数传入,route()传入空字符串", path="/name4")
ns5 = Namespace("demo5 management", "add_namespace()和Namespace()都有path参数传入,route()未传参", path="/name5")

@ns1.route("/route1")
class Demo1(Resource):
    def get(self):
        return "demo1 get"

    def post(self):
        return "demo1 post"

@ns2.route("/route2")
class Demo2(Resource):
    def get(self):
        return "demo2 get"

    def post(self):
        return "demo2 post"

@ns3.route("/route3")
class Demo3(Resource):
    def get(self):
        return "demo3 get"

@ns4.route("")
class Demo4(Resource):
    def get(self):
        return "demo4 get"

@ns5.route()
class Demo5(Resource):
    def get(self):
        return "demo5 get"

api.add_namespace(ns1, "/api_add")
api.add_namespace(ns2)
api.add_namespace(ns3)
api.add_namespace(ns4, "/api_add4")
api.add_namespace(ns5, "/api_add5")

if __name__=="__main__":
    app.run()

Execute the script (start the flask service), access the root path of the interface, and the results are as follows:
insert image description here

swagger interface document configuration

There are two ways to configure the swagger document in flask-rest:

  • The first method: use @Api对象.doc()or @namespace对象.doc()decorate the request method
  • The second method: use parser = api.parser()the verification and input of parameters with `@api.expect(parser) decorator

It is recommended to use the second method

doc() method

The content of the py script is:

from flask import Flask, request
from flask_restx import Api, Resource, Namespace, fields

app = Flask(__name__)
api = Api(app)

ns = Namespace("分类名称", description="分类的描述")

@ns.route("")
class Demo(Resource):
    # doc()种对请求参数params(即url参数)进行字段说明
    @ns.doc(params={
    
    "id": "用户编号", "subject": "科目"})
    def get(self):
        return {
    
    "code": 0, "data": request.args}

    #
    post_check_model = api.model("PostModel", {
    
    
        "name": fields.String(description="姓名", required=True),
        "age": fields.Integer(min=0),
        "gender": fields.String(description="性别", enum=["男", "女"])
    })
    @ns.doc(body=post_check_model)
    def post(self):
        data = request.json
        return f"{
      
      data.get('name')}, {
      
      data.get('age')}岁, {
      
      data.get('gender')}性"

api.add_namespace(ns, "/demo")

if __name__=="__main__":
    app.run(debug=True)

Execute the script (start the flask service), access the root path:
insert image description here

The doc() method is equivalent to describing the interface fields, and does not restrict the interface fields well, so this method is not recommended.

Api object parser method

The recommended swagger interface document configuration steps are as follows:

  • Step 1: In the class, parser()obtain the RequestParser object through the method of the Api object
  • Step 2: In the RequestParser object, add_argument()set the interface request field through the method
  • Step 3: In the corresponding request method, add the decorator of the namespace object, and expect()pass in the RequestParser object through the method, indicating that the interface is defined by the interface field of the RequestParser object.

The method of the RequestParser object add_argument(*args, **kwargs)is to configure the interface request field, and the relevant key parameters are described as follows:

  • The first parameter is the parameter name, which is the field name of the interface request field
  • Followed by keyword parameters, commonly used keywords are:
    • type: type
      • Parameter value: int (integer), bool (Boolean), float (floating point), string (string), FileStorage (file object)
      • Description: Control the type of the interface field value, specify the data type of the interface field value
    • required: constraint control
      • Parameter values: True, False
      • Description: If it is set to True, it means that the field is mandatory, and False means it is optional
    • help: field description, string, can describe the field
    • choices: enumeration parameters
      • Description: The parameter value should be an object such as a list, tuple, etc., indicating that the field value must be in the specified range
    • location: corresponds to the attributes in the flask.request object
      • Parameter value: The parameter value is the attribute in the flask.request object, such as args, form, json, files, headers, etc.
      • Description: Used to specify the location of the field, such as in url request parameters, form forms or json data

Example:

from flask import Flask, request
from flask_restx import Api, Resource, Namespace
from werkzeug.datastructures import FileStorage

app = Flask(__name__)
api = Api(app)

ns = Namespace("分类名称", description="分类的描述")

@ns.route("")
class Demo(Resource):
    # 定义RequestParser解析器对象
    get_parser = api.parser()
    # 通过RequestParser对象添加接口请求字段参数配置
    get_parser.add_argument("id", type=int, help="身份证号", location="args")
    get_parser.add_argument("subject", type=str, help="科目", location="args")

    # 通过Namespace对象的expect(RequestParser对象)方法,对get请求进行装饰(即对该get请求接口字段指定字段配置
    @ns.expect(get_parser)
    def get(self):
        return {
    
    "code": 0, "args_data": request.args}

    post_parser = api.parser()
    post_parser.add_argument("file_data", type=FileStorage, help="上传文件", location="files")
    post_parser.add_argument("account", type=str, help="帐号", location="form")
    post_parser.add_argument("password", help="密码", location="form")
    @ns.expect(post_parser)
    def post(self):
        return {
    
    "status_code": "success", "form_data": request.form, "file_name": request.files.get("file_data").filename}

    put_parser = api.parser()
    put_parser.add_argument("name", type=str, help="姓名", location="json", required=True)
    put_parser.add_argument("age", type=int, help="年龄", location="json")
    put_parser.add_argument("gender", help="性别", choices=["男", "女"], location="json")
    @ns.expect(put_parser)
    def put(self):
        return {
    
    "code": 0, "message": "success", "json_data": request.json}

api.add_namespace(ns, "/demo")

if __name__=="__main__":
    app.run(debug=True)

Execute the script (start the flask service), access the root directory and send the request, the results are as follows:
insert image description here
注意:Swagger 的检验比较虚(即字段校验一般不生效),真要强制约束请求信息,还是要在代码里

Guess you like

Origin blog.csdn.net/wenxiaoba/article/details/128053226