Vapor 3解码内容:是否要捕获多种帖子格式?

问题描述 投票:2回答:1

我有一个控制器,其创建动作我想像这样接受JSON:

{ "foo": "bar" }

或类似这样:

{ "widget": { "foo": "bar" } }

也就是说,我要接受小部件或包含在包含对象中的小部件。当前,控制器的create动作看起来很像这样:

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)
    }
  }
}

WidgetCreateObject看起来像:

struct WidgetCreateObject { var foo: String? }

[WidgetCreateHolder看起来像:

struct WidgetCreateHolder { var widget: WidgetCreateObject }

也就是说,我的create动作应该try创建一个持有人,但是如果失败,它将捕获错误并尝试仅创建内部对象(WidgetCreateObject)。但是,当我将此代码部署到Heroku并仅使用内部对象JSON发出请求时,就会在日志中得到此信息:

[ ERROR ] DecodingError.keyNotFound: Value required for key 'widget'. (ErrorMiddleware.swift:26)

即使我试图捕获该错误!

如何获得创建动作以接受两种不同格式的JSON对象?

swift vapor vapor-fluent
1个回答
0
投票

想通!

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

[幸运的是,Future有一系列以catch开头的方法;我感兴趣的是catchFlatMap,它接受Error -> Future<Decodable>的闭包。此方法“捕获”被调用的Future中引发的错误,并使用任何下游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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.