python - 如何使用flaskrestplus设计web的api实现?

标签 python flask swagger flask-restplus

我第一次在flask中编写REST api,

所以现在我有这样的东西:

import uuid
import pytz
from datetime import datetime
from flask_restplus import Resource, Api, fields
from ..models import publicip_schema

from ..controller import (
    jsonified,
    get_user_ip,
    add_new_userIp,
    get_specificIp,
    get_all_publicIp
    )

from flask import request, jsonify

from src import app
from src import db
from src import models

api = Api(app, endpoint="/api", versio="0.0.1", title="Capture API", description="Capture API to get, modify or delete system services")

add_userIp = api.model("Ip", {"ip": fields.String("An IP address.")})
get_userIp = api.model("userIp", {
    "ipid": fields.String("ID of an ip address."), 
    "urlmap" : fields.String("URL mapped to ip address.")
    })

class CaptureApi(Resource):

    # decorator = ["jwt_required()"]

    # @jwt_required()
    @api.expect(get_userIp)
    def get(self, ipid=None, urlmap=None):
        """
           this function handles request to provide all or specific ip
        :return:
        """
        # handle request to get detail of site with specific location id.
        if ipid:
            ipobj = get_user_ip({"id": ipid})
            return jsonified(ipobj)

        # handle request to get detail of site based on  site abbreviation
        if urlmap:
            locate = get_user_ip({"urlmap": urlmap})
            return jsonified(locate)

        return jsonify(get_all_publicIp())

    # @jwt_required()
    @api.expect(add_userIp)
    def post(self, username=None):
        """
            Add a new location.
            URI /location/add
        :return: json response of newly added location
        """
        data = request.get_json(force=True)
        if not data:
            return jsonify({"status": "no data passed"}), 200

        if not data["ip"]:
            return jsonify({"status" : "please pass the new ip you want to update"})

        if get_user_ip({"ipaddress": data["ip"]}):
                return jsonify({"status": "IP: {} is already registered.".format(data["ip"])})

        _capIpObj = get_user_ip({"user_name": username})

        if _capIpObj:
            # update existing ip address
            if "ip" in data:
                if _capIpObj.ipaddress == data["ip"]:
                    return jsonify({"status": "nothing to update."}), 200
                else:
                    _capIpObj.ipaddress = data["ip"]
            else:
                return jsonify({
                    "status" : "please pass the new ip you want to update"
                    })

            db.session.commit()
            return jsonified(_capIpObj)
        else:
            device = ""
            service = ""
            ipaddress = data["ip"]
            if "port" in data:
                port = data["port"]
            else:
                port = 80
            if "device" in data:
                device = data["device"]
            if "service" in data:
                service = data["service"]
            date_modified = datetime.now(tz=pytz.timezone('UTC'))
            urlmap = str(uuid.uuid4().get_hex().upper()[0:8])    
            new_public_ip = add_new_userIp(username, ipaddress, port, urlmap, device, service, date_modified)
            return publicip_schema.jsonify(new_public_ip)


api.add_resource(
    CaptureApi,
    "/getallips",  # GET
    "/getip/id/<ipid>",  # GET
    "/getip/urlmap/<urlmap>",  # GET
    "/updateip/username/<username>" # POST
                 )

我遇到了两个问题

  1. 如果我指定

    get_userIp = api.model("userIp", { "ipid": fields.String("ID of an ip address."), "urlmap" : fields.String("URL mapped to ip address.") })

并添加 @api.expect(get_userIp)在上面的 get 方法上。我被迫传递具有任何值的可选参数(甚至是从“/getallips”获取所有 IP 的列表):请参见下面的屏幕截图。

enter image description here 但这些选项参数并不是所有 IP 都必需的,但我确实需要使用这些参数来基于 ipid 获取 ip ,或urlmap使用get方法。

  • 查看 flask_restplus.Api 生成的 swagger 文档我看到了
  • 所有端点的 get 和 post ,而我只定义了端点 get 和 post 。所以从技术上来说updateip/username/<username>不应列出get enter image description here

    如何解决这个问题?

    最佳答案

    好问题!您可以通过定义单独的 Resource 来解决这两个问题。每个端点的子类。下面是一个示例,其中我分割了“/getallips”、“/getip/id/”和“/getip/urlmap/”的端点。

    Ip = api.model("Ip", {"ip": fields.String("An IP address.")})
    Urlmap = api.model("UrlMap", {"urlmap": fields.String("URL mapped to ip address.")})
    
    @api.route("/getallips")
    class IpList(Resource):
        def get(self):
            return jsonify(get_all_publicIp())
    
    @api.route("/getip/id/<ipid>")
    class IpById(Resource):
        @api.expect(Ip)
        def get(self, ipid):
            ipobj = get_user_ip({"id": ipid})
            return jsonified(ipobj)
    
    @api.route("/getip/urlmap/<urlmap>")
    class IpByUrlmap(Resource):
        @api.expect(Urlmap)
        def get(self, urlmap):
            ipobj = get_user_ip({"id": ipid})
            return jsonified(ipobj)
    

    请注意,您解决了 expect免费解决问题 - 因为每个端点现在都完全定义了其接口(interface),所以很容易对其附加明确的期望。您还解决了“为不应定义的端点获取和发布”的问题,您可以决定每个端点是否应该有 getpost .

    我正在使用 api.route 装饰器而不是调用 api.add_resource由于个人喜好,每个类(class)。您可以通过调用 api.add_resource(<resource subclass>, <endpoint>) 获得相同的行为对于每个新的Resource子类(例如 api.add_resource(IpList, "/getallips") )

    关于python - 如何使用flaskrestplus设计web的api实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48802421/

    相关文章:

    python - 计算 python 列表中对象的出现次数

    jquery - 使用 jQuery 在 Flask/Jinja2 中具有不同 CSS 值的一类

    asp.net - SwaggerSchema 不适用于我自己的对象

    c# - .Net Core 2.2/Kestrel/Swagger 禁用分块/编码

    python - 无法安装 jaxlib

    python - CreateProcessW 失败错误 :2 ssh_askpass: posix_spawn: No such file or directory Host key verification failed, 远程服务器上的 jupyter notebook

    python - 这段python代码中的大于号是什么意思?

    python - 如何使用 Flask 和 Celery 定期运行一个函数?

    python - Flask 服务器启动问题 - 地址已在使用中

    c# - Swagger 不工作 Asp.net Core 如何打开 swagger ui