简体   繁体   English

如何在python中验证POST请求的json / xml主体

[英]How to validate json/xml body of a POST request in python

I am trying t write a web controller for an API with GET, POST, PUT functionalities. 我正在尝试为具有GET,POST,PUT功能的API编写Web控制器。 1. In the method that handles the requests , especially POST and PUT, I want to validate if the required keys/fields are present in the request body. 1.在处理请求的方法中,尤其是POST和PUT,我想验证请求正文中是否存在必需的键/字段。 2. I also want to check the authorization key present in the request header and throw unauthorized error etc. as response. 2.我还想检查请求标头中存在的授权密钥,并抛出未授权的错误等作为响应。

Is there an elegant way of doing this in python, write multiple if...else doesn't look elegant. 在python中是否有一种优雅的方式来执行此操作, if...else看起来不那么优雅,请编写多个。

I have the following code which handles the request body: 我有以下代码可以处理请求正文:

from werkzeug.wrappers import BaseResponse as Response
.
.
.
    root = ET.fromstring(data)
            for child in root:
                order_completed_date = child.find('Order_Completed_Date')
                if order_completed_date is None:
                    #return json.loads({"status":"400", "message":"Order_Completed_Date is missing"})
                    return Response('Bad Request, Order_Complete_At missing', status=400)
                else:
                    order_completed_date = order_completed_date.text
                order_id = child.find('Order_Number')
                if order_id is None:
                    return Response('Bad Request, Order_Number missing', status=400) 
                else:
                    order_id = order_id.text
                product_id =child.find('SKU')
                if product_id is None:
                    return Response("Bad request, SKU is missing", status=400)
                else:
                    product_id = product_id.text
                .
                .
                .

So on, I'm writing if else for each field 依此类推,我正在为每个领域写

We've got some code, so we can look at how to refactor it. 我们有一些代码,因此我们可以看看如何重构它。

You essentially have minor variations on this code over and over: 基本上,您在此代码上会有一些细微的变化:

order_completed_date = child.find('Order_Completed_Date')
if order_completed_date is None:
    #return json.loads({"status":"400", "message":"Order_Completed_Date is missing"})
    return Response('Bad Request, Order_Complete_At missing', status=400)
else:
    order_completed_date = order_completed_date.text

So, how could we turn that into a function? 那么,我们如何将其转换为功能呢?

First, just turn it into a function and see what's wrong with it: 首先,只需将其转换为函数,然后看看有什么问题:

def find_key():
    order_completed_date = child.find('Order_Completed_Date')
    if order_completed_date is None:
        return Response('Bad Request, Order_Complete_At missing', status=400)
    else:
        order_completed_date = order_completed_date.text

So, the first problem is that child value. 因此,第一个问题是child价值。 It's not a constant; 这不是一个常数。 it's different each time through the loop, so we need to take that as a parameter.* 每次循环都不同,因此我们需要将其作为参数。*

* Well, we could define find_key locally, and get child as a closure variable, but let's keep it simple for now. *好吧,我们可以在本地定义find_key ,并将child作为闭包变量,但现在让我们保持简单。

Similarly, while 'Order_Completed_Date' isn't different each time through the loop, it is different for each different key, so we need to take that as well.* 同样,虽然'Order_Completed_Date'在整个循环中每次都不相同,但对于每个不同的键来说都是不同的,因此我们也需要考虑这一点。*

* There's also an 'Order_Complete_At' string, but that seems to be a typo for 'Order_Completed_Date' . *还有一个'Order_Complete_At'字符串,但这似乎是'Order_Completed_Date'的错字。 If it isn't, then you'll need to add another parameter, like key_error_name , that you can use for that. 如果不是,则需要添加另一个参数,例如key_error_name

The variable name order_completed_date doesn't have to change, because local variable names don't mean anything to Python—but it's obviously misleading to a human reader if we use it as a generic name for "the value for each key". 变量名order_completed_date 没有改变,因为如果我们把它作为“为每个键的值”的通用名称局部变量名称不意味着什么Python的,但它显然误导人的读者。

Finally, the big problem is what we return . 最后,最大的问题是我们的回报 We have two different kinds of things we could return—a node's text, or an error Response. 我们可以返回两种不同的东西-节点的文本或错误响应。 We could return the former and raise an exception with the latter. 我们可以return前者,而对后者raise例外。 Or return a pair of things, a text-or-error and a flag that tells us which is which. 或返回一对东西,一个文本或错误和一个标志,告诉我们哪个是哪个。 Or we could return a text and an error, one of which is None . 或者我们可以返回一个文本和一个错误,其中一个是None The exception seems like the most complicated, but it automatically gives us a "non-local return", a way to break out of the rest of the function without having to check each return value one by one. 异常似乎是最复杂的,但是它会自动为我们提供“非本地返回”,这是一种无需使用一个函数就检查每个返回值的其他函数的方法。

So: 所以:

def find_key(child, key):
    value = child.find(key)
    if value is None:
        raise KeyError(key)
    else:
        return value.text

And now: 现在:

try:
    for child in root:
        order_completed_date = find_key(child, 'Order_Completed_Date')
        order_id = find_key(child, 'Order_Number')
        product_id = find_key(child, 'SKU')
        # ...
except KeyError as e:
    return Response("Bad request, {} is missing".format(e.args[0]), status=400)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM