Swift Vapor 3解码内容:多个post格式的do/catch?

Swift Vapor 3解码内容:多个post格式的do/catch?,swift,vapor,vapor-fluent,Swift,Vapor,Vapor Fluent,我有一个控制器,其创建操作我希望接受JSON,如下所示: { "foo": "bar" } { "widget": { "foo": "bar" } } 或者像这样: { "foo": "bar" } { "widget": { "foo": "bar" } } 也就是说,我想要接受小部件或包装在包含对象中的小部件。当前,“我的控制器”的创建操作看起来非常像: func createHandler(_ req: Request) throws -> Future<Widget

我有一个控制器,其创建操作我希望接受JSON,如下所示:

{ "foo": "bar" }
{ "widget": { "foo": "bar" } }
或者像这样:

{ "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: $0.widget)
    }
  } catch DecodingError.keyNotFound {
    return try req.content.decode(WidgetCreateObject.self).flatMap(to: Widget.self) {
      return createWidget(from: $0)
    }
  }
}
其中
WidgetCreateHolder
看起来像:

struct WidgetCreateHolder { var widget: WidgetCreateObject }
也就是说,我的创建操作应该
尝试创建一个holder,但是如果失败,它应该捕获错误并尝试只创建内部对象(一个
WidgetCreateObject
)。但是,当我将此代码部署到Heroku并仅使用内部对象JSON发出请求时,我会在日志中看到:

[ ERROR ] DecodingError.keyNotFound: Value required for key 'widget'. (ErrorMiddleware.swift:26)
即使我试图抓住那个错误

如何让我的创建操作接受两种不同格式的JSON对象?

解决了这个问题

decode
方法返回一个
Future
,这样实际的解码(以及由此产生的错误)会在以后发生,而不是在do/catch期间。这意味着无法使用此do catch捕捉错误

幸运的是,
Future
s有一系列的方法,前面有
catch
;我感兴趣的是
catchFlatMap
,它接受来自
Error->Future
的闭包。这个方法“捕获”在被调用的将来抛出的错误,并将错误传递给闭包,在任何下游的将来使用结果

因此,我可以将代码更改为:

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: $0)
        }
    }).flatMap(to: Widget.self) {
        return createWidget(from: $0.widget)
    }
}
func createHandler(\ureq:Request)抛出->未来{
返回try-req.content.decode(WidgetCreateHolder.self).catchFlatMap({in
返回try req.content.decode(WidgetCreateObject.self).map(到:WidgetCreateHolder.self){
返回WidgetCreateHolder(小部件:$0)
}
}).flatMap(到:Widget.self){
返回createWidget(发件人:$0.widget)
}
}

有两个结构都符合可解码的要求。让我们调用结构,其中widget为A1,而widget为A2。尝试将其解码为A1,如果失败,尝试将其解码为A2。在第一种情况下,使用map操作符将A1转换为A2。