如何为 404 页面创建 OpenAPI 部分?

Posted

技术标签:

【中文标题】如何为 404 页面创建 OpenAPI 部分?【英文标题】:How do I create the OpenAPI section for the 404 page? 【发布时间】:2021-12-30 08:13:31 【问题描述】:

我正在使用OpenApi 3。我使用的工具Owasp Zap 查看 OpenAPI 文档并创建虚假请求。当它收到 404 时,它会抱怨它没有 OpenAPI 承诺的媒体类型。

但我没有在 OpenAPI 文档中写任何关于如何处理 404 的内容。显然,我无法编写无限数量的错误端点并记录它们返回 404。

在 OpenAPI yaml 或 json 中记录此内容的正确方法是什么?

这是一个最小的 yaml 文件...我确信这个文件确实说明了 404,即。 404 不在合同中,因此工具抱怨 404 是有效响应,但 404 是资源丢失时网站应返回的内容

---
"openapi": "3.0.0"

paths:
    /Foo/:
        get:
            responses:
                "200":
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/Foo"
                default:
                    description: Errors
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/Error"
components:
    schemas:
        Foo:
            type: object
            required:
                - name
            properties:
                name:
                    type: string
        Error:
            type: object
            required:
                - error
            properties:
                error:
                    type: string
                message:
                    type: string
                data:
                    type: object

【问题讨论】:

这可能是您托管 API 的网络服务器的问题吗? 问题可能是任何事情。值得一提的是,它是一个 python 应用程序——在烧瓶之上的连接。 措辞似乎有点不清楚:ZAP 是按照模式(即使用指定的路径)还是随机路径生成请求?后一种情况似乎更像是工具的问题——您可以添加一个带有 404 响应的 / 路径,但这似乎很麻烦,特别是因为 OpenAPI 只允许一个级别的模式匹配 (github.com/OAI/OpenAPI-Specification/issues/892) @ChrisAdams - 它还生成像 admin.php 这样的端点,然后抱怨它得到了 404。我会试试,我猜它相当于 "/Param" 其中 Param 是不存在的端点。 当 OpenAPI 的增强功能落地时肯定会很好,因为您可以记录例如一种常见的错误格式,但我将其归类为 ZAP 中的缺陷:如果它做了 API 合同没有说明它可以做的事情并获得标准状态码作为回报,那不是问题。 【参考方案1】:

这已经提出但尚未实施:https://github.com/OAI/OpenAPI-Specification/issues/521

在 cmets 中有人提出了一个建议:https://github.com/OAI/OpenAPI-Specification/issues/521#issuecomment-513055351,这会减少你的代码,但你仍然需要为 N 个路径 * M 个方法插入 N*M 个条目。

由于我们没有能力根据我们的需求更改规范,剩下的就是我们自己调整。

从您的个人资料来看,您似乎是 Windows 用户。例如,您可以为您的 .yaml 文件(Add menu item to windows context menu only for specific filetype、Adding a context menu item in Windows for a specific file extension)创建一个新的资源管理器上下文菜单,并使其运行自动填充文件的脚本。

这里是一个名为yamlfill404.py 的示例python 脚本,它将以path/to/pythonexecutable/python.exe path/to/python/script/yamlfill404.py %1 之类的方式在上下文调用中使用,其中%1 是被右键单击的文件的路径。

Python 文件:

import yaml
from sys import argv
import re

order = ['openapi','paths','components']
level0re = re.compile('(?<=\n)[^ ][^:]+')

def _propfill(rootnode, nodes, value):
    if len(nodes) == 1:
        rootnode[nodes[0]] = value
    if len(nodes) > 1:
        nextnode = rootnode.get(nodes[0]) 
        if rootnode.get(nodes[0]) is None:
            nextnode = 
            rootnode[nodes[0]] = nextnode
        _propfill(nextnode, nodes[1:], value)

def propfill(rootnode, nodepath, value):
    _propfill(rootnode, [n.replace('__slash__','/') for n in nodepath.replace('\/','__slash__').split('/')], value)

def yamlfill(filepath):
    with open(filepath, 'r') as file:
        yamltree = yaml.safe_load(file)
    #propfill(yamltree, 'components/schemas/notFoundResponse/...', '')
    propfill(yamltree, 'components/responses/notFound/description', 'Not found response')
    propfill(yamltree, 'components/responses/notFound/content/application\/json/schema/$ref', '#/components/schemas/notFoundResponse')
    responses = [mv['responses'] if 'responses' in mv else [] for pk,pv in (yamltree['paths'].items() if 'paths' in yamltree else []) for mk,mv in pv.items()]
    for response in responses:
        propfill(response, '404/$ref', '#/components/responses/notFound')
    yamlstring = yaml.dump(yamltree)
    offsets = [i[1] for i in sorted([(order.index(f.group(0)) if f.group(0) in order else len(order),f.start()-1) for f in [f for f in level0re.finditer('\n'+yamlstring)]])]
    offsets = [(offset,(sorted([o for o in offsets if o > offset]+[len(yamlstring)-1])[0])) for offset in offsets]
    with open(filepath[:-5]+'_404.yaml', 'w') as file:
        file.write(''.join(['\n'+yamlstring[o[0]:o[1]] for o in offsets]).strip())

yamlfill(argv[-1])

它处理%1,即path/to/original.yaml,并将其保存为path/to/original_404.yaml(但您可以更改它以覆盖原来的)。

此示例脚本更改了 yaml 格式(引号类型、间距、排序等),因为使用了 pyyaml 的库。我不得不用order = ['openapi','paths','components'] 重新排序文件,因为它失去了排序。为了减少干扰,也许更适合手动插入。也许一个只使用正则表达式。 Maye 使用awk,有很多方法。

不幸的是,这只是一个 hack 而不是解决方案。

【讨论】:

以上是关于如何为 404 页面创建 OpenAPI 部分?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 ASP.NET MVC 处理“未找到 404 页面”查询的全部路由?

如何为 404 Not Found 创建自定义响应消息?

如何为Android创建小于O的通知通道

如何为某些 HTML 页面部分的屏幕阅读器设置优先级?

在 Lumen 中创建自定义错误页面

哈希表的插入复杂度如何为 O(1)