Vapor 3 解码内容:do/catch 用于多种 post 格式?
Vapor 3 decoding content: do/catch for multiple post formats?
我有一个控制器,我想接受其创建操作 JSON 要么像这样:
{ "foo": "bar" }
或者像这样:
{ "widget": { "foo": "bar" } }
也就是说,我想接受小部件或包裹在包含对象中的小部件。目前,我的控制器的创建操作看起来很像这样:
func createHandler(_ req: Request) throws -> Future<Widget> {
do {
return try req.content.decode(WidgetCreateHolder.self).flatMap(to: Widget.self) {
return createWidget(from: [=14=].widget)
}
} catch DecodingError.keyNotFound {
return try req.content.decode(WidgetCreateObject.self).flatMap(to: Widget.self) {
return createWidget(from: [=14=])
}
}
}
其中 WidgetCreateObject
看起来像:
struct WidgetCreateObject { var foo: String? }
WidgetCreateHolder
看起来像:
struct WidgetCreateHolder { var widget: WidgetCreateObject }
也就是说,我的创建操作应该 try
来创建一个持有者,但如果失败,它应该捕获错误并尝试只创建内部对象 (a WidgetCreateObject
)。但是,当我将此代码部署到 Heroku 并仅使用内部对象 JSON 发出请求时,我在日志中得到了这个:
[ ERROR ] DecodingError.keyNotFound: Value required for key 'widget'. (ErrorMiddleware.swift:26)
即使我正在尝试捕获该错误!
如何让我的创建操作接受两种不同格式的 JSON 对象?
想通了!
decode
方法 returns a Future
,这样实际的解码(以及错误)发生在稍后,而不是在 do/catch 期间。这意味着无法使用此 do catch 捕获错误。
幸运的是,Future
s 有一系列以catch
开头的方法;我感兴趣的是 catchFlatMap
,它接受来自 Error -> Future<Decodable>
的闭包。此方法 'catches' 在被调用的 Future 中抛出的错误,并将错误传递给闭包,在任何下游 futures 中使用结果。
所以我能够将我的代码更改为:
func createHandler(_ req: Request) throws -> Future<Widget> {
return try req.content.decode(WidgetCreateHolder.self).catchFlatMap({ _ in
return try req.content.decode(WidgetCreateObject.self).map(to: WidgetCreateHolder.self) {
return WidgetCreateHolder(widget: [=10=])
}
}).flatMap(to: Widget.self) {
return createWidget(from: [=10=].widget)
}
}
我有一个控制器,我想接受其创建操作 JSON 要么像这样:
{ "foo": "bar" }
或者像这样:
{ "widget": { "foo": "bar" } }
也就是说,我想接受小部件或包裹在包含对象中的小部件。目前,我的控制器的创建操作看起来很像这样:
func createHandler(_ req: Request) throws -> Future<Widget> {
do {
return try req.content.decode(WidgetCreateHolder.self).flatMap(to: Widget.self) {
return createWidget(from: [=14=].widget)
}
} catch DecodingError.keyNotFound {
return try req.content.decode(WidgetCreateObject.self).flatMap(to: Widget.self) {
return createWidget(from: [=14=])
}
}
}
其中 WidgetCreateObject
看起来像:
struct WidgetCreateObject { var foo: String? }
WidgetCreateHolder
看起来像:
struct WidgetCreateHolder { var widget: WidgetCreateObject }
也就是说,我的创建操作应该 try
来创建一个持有者,但如果失败,它应该捕获错误并尝试只创建内部对象 (a WidgetCreateObject
)。但是,当我将此代码部署到 Heroku 并仅使用内部对象 JSON 发出请求时,我在日志中得到了这个:
[ ERROR ] DecodingError.keyNotFound: Value required for key 'widget'. (ErrorMiddleware.swift:26)
即使我正在尝试捕获该错误!
如何让我的创建操作接受两种不同格式的 JSON 对象?
想通了!
decode
方法 returns a Future
,这样实际的解码(以及错误)发生在稍后,而不是在 do/catch 期间。这意味着无法使用此 do catch 捕获错误。
幸运的是,Future
s 有一系列以catch
开头的方法;我感兴趣的是 catchFlatMap
,它接受来自 Error -> Future<Decodable>
的闭包。此方法 'catches' 在被调用的 Future 中抛出的错误,并将错误传递给闭包,在任何下游 futures 中使用结果。
所以我能够将我的代码更改为:
func createHandler(_ req: Request) throws -> Future<Widget> {
return try req.content.decode(WidgetCreateHolder.self).catchFlatMap({ _ in
return try req.content.decode(WidgetCreateObject.self).map(to: WidgetCreateHolder.self) {
return WidgetCreateHolder(widget: [=10=])
}
}).flatMap(to: Widget.self) {
return createWidget(from: [=10=].widget)
}
}