从 URL 参数中解析分隔和嵌套的字段名称以进行部分响应
Parse delimited and nested field names from URL parameter for partial response
在基于 Flask-RESTful
的 API 中,我希望允许客户端通过 [=16] 检索 JSON 部分 响应=] 参数。它列出了将用于构建较大原件的部分表示的字段名称(JSON 对象的键)。
这可能是最简单的逗号分隔列表:
GET /v1/foobar?fields=name,id,date
这可以通过 webargs 的 DelimitedList 架构字段轻松完成,对我来说没有问题。
但是,为了允许 嵌套 对象的键被表示,分隔的字段列表可以包括任意嵌套的键,这些键括在匹配的括号中:
GET /v1/foobar?fields=name,id,another(name,id),date
{
"name": "",
"id": "",
"another": {
"name": "",
"id": ""
},
"date": ""
}
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
{
"id": "",
"one": {
"id: "",
"two": {
"id": "",
"three": {
"id": ""
},
"date": ""
}
},
"date": ""
}
GET /v1/foobar?fields=just(me)
{
"just": {
"me: ""
}
}
我的问题有两个:
有没有办法在本地使用 webargs
和 marshmallow
执行此操作(验证和反序列化)?
如果没有,我将如何使用像 pyparsing
这样的解析框架来做到这一点?非常感谢任何关于 BNF 语法应该是什么样子的提示。
Pyparsing 有几个有用的内置插件,delimitedList
和 nestedExpr
。这是一个带注释的片段,它为您的值构建了一个解析器。 (我还提供了一个示例,您的列表元素可能不仅仅是简单的字母单词):
import pyparsing as pp
# placeholder element that will be used recursively
item = pp.Forward()
# your basic item type - expand as needed to include other characters or types
word = pp.Word(pp.alphas + '_')
list_element = word
# for instance, add support for numeric values
list_element = word | pp.pyparsing_common.number
# retain x(y, z, etc.) groupings using Group
grouped_item = pp.Group(word + pp.nestedExpr(content=pp.delimitedList(item)))
# define content for placeholder; must use '<<=' operator here, not '='
item <<= grouped_item | list_element
# create parser
parser = pp.Suppress("GET /v1/foobar?fields=") + pp.delimitedList(item)
您可以使用 runTests
:
测试任何 pyparsing 表达式
parser.runTests("""
GET /v1/foobar?fields=name,id,date
GET /v1/foobar?fields=name,id,another(name,id),date
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
GET /v1/foobar?fields=just(me)
GET /v1/foobar?fields=numbers(1,2,3.7,-26e10)
""", fullDump=False)
给出:
GET /v1/foobar?fields=name,id,date
['name', 'id', 'date']
GET /v1/foobar?fields=name,id,another(name,id),date
['name', 'id', ['another', ['name', 'id']], 'date']
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
['id', ['one', ['id', ['two', ['id', ['three', ['id']], 'date']]]], 'date']
GET /v1/foobar?fields=just(me)
[['just', ['me']]]
GET /v1/foobar?fields=numbers(1,2,3.7,-26e10)
[['numbers', [1, 2, 3.7, -260000000000.0]]]
在基于 Flask-RESTful
的 API 中,我希望允许客户端通过 [=16] 检索 JSON 部分 响应=] 参数。它列出了将用于构建较大原件的部分表示的字段名称(JSON 对象的键)。
这可能是最简单的逗号分隔列表:
GET /v1/foobar?fields=name,id,date
这可以通过 webargs 的 DelimitedList 架构字段轻松完成,对我来说没有问题。
但是,为了允许 嵌套 对象的键被表示,分隔的字段列表可以包括任意嵌套的键,这些键括在匹配的括号中:
GET /v1/foobar?fields=name,id,another(name,id),date
{
"name": "",
"id": "",
"another": {
"name": "",
"id": ""
},
"date": ""
}
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
{
"id": "",
"one": {
"id: "",
"two": {
"id": "",
"three": {
"id": ""
},
"date": ""
}
},
"date": ""
}
GET /v1/foobar?fields=just(me)
{
"just": {
"me: ""
}
}
我的问题有两个:
有没有办法在本地使用
webargs
和marshmallow
执行此操作(验证和反序列化)?如果没有,我将如何使用像
pyparsing
这样的解析框架来做到这一点?非常感谢任何关于 BNF 语法应该是什么样子的提示。
Pyparsing 有几个有用的内置插件,delimitedList
和 nestedExpr
。这是一个带注释的片段,它为您的值构建了一个解析器。 (我还提供了一个示例,您的列表元素可能不仅仅是简单的字母单词):
import pyparsing as pp
# placeholder element that will be used recursively
item = pp.Forward()
# your basic item type - expand as needed to include other characters or types
word = pp.Word(pp.alphas + '_')
list_element = word
# for instance, add support for numeric values
list_element = word | pp.pyparsing_common.number
# retain x(y, z, etc.) groupings using Group
grouped_item = pp.Group(word + pp.nestedExpr(content=pp.delimitedList(item)))
# define content for placeholder; must use '<<=' operator here, not '='
item <<= grouped_item | list_element
# create parser
parser = pp.Suppress("GET /v1/foobar?fields=") + pp.delimitedList(item)
您可以使用 runTests
:
parser.runTests("""
GET /v1/foobar?fields=name,id,date
GET /v1/foobar?fields=name,id,another(name,id),date
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
GET /v1/foobar?fields=just(me)
GET /v1/foobar?fields=numbers(1,2,3.7,-26e10)
""", fullDump=False)
给出:
GET /v1/foobar?fields=name,id,date
['name', 'id', 'date']
GET /v1/foobar?fields=name,id,another(name,id),date
['name', 'id', ['another', ['name', 'id']], 'date']
GET /v1/foobar?fields=id,one(id,two(id,three(id),date)),date
['id', ['one', ['id', ['two', ['id', ['three', ['id']], 'date']]]], 'date']
GET /v1/foobar?fields=just(me)
[['just', ['me']]]
GET /v1/foobar?fields=numbers(1,2,3.7,-26e10)
[['numbers', [1, 2, 3.7, -260000000000.0]]]