【问题标题】:How to transform this side-effect into an elegant chaining of Vapor operations?如何将这种副作用转化为优雅的 Vapor 操作链?
【发布时间】:2020-11-19 22:13:07
【问题描述】:

我开始使用 Vapor 来运行 API,但我无法找到一种优雅的方式来执行以下操作:(1) 加载 Fluent 关系并 (2) 等待响应(3) 响应原始请求之前的 HTTP 回调。

在我将现实生活中的实体转换为行星和恒星以维护 Vapor 文档中的示例之后,这就是我最终编写的代码。它可以工作™️,但我无法实现良好的操作链☹️。

    func flagPlanetAsHumanFriendly(req: Request) throws -> EventLoopFuture<Planet> {
        Planet(req.parameters.get("planetID"), on: req.db)
            .unwrap(or: Abort(.notFound))
            .flatMap { planet in
                // I load the star because I need its ID for the HTTP callback
                _ = planet.$star.load(on: req.db).map {
                    let uri = URI(scheme: "http", host: "localhost", port: 4200, path: "/webhooks/star")
                    // HTTP Callback
                    req.client.post(uri) { req in
                        try req.content.encode(
                            WebhookDTO(
                                starId: planet.star.id!,
                                status: .humanFriendly,
                                planetId: planet.id!
                            ),
                            using: JSONEncoder()
                        )
                    }
                    .map { res in
                        debugPrint("\(res)")
                        return
                    }
                }

                // Couldn't find a way to wait for the response, so the HTTP callback is a side-effect
                // and its response is not used in the original HTTP response...
                // If the callback fails, my API can't report it. 
                planet.state = .humanFriendly
                return planet.save(on: req.db).map { planet }
            }
    }

问题 #1。结合2个EventLoopFuture

我的第一个问题是我找不到加载父关系同时将实体保持在范围内的方法。

Planet(req.parameters.get("planetID"), on: req.db)
    .unwrap(or: Abort(.notFound))
    .flatMap { planet in // planet is in the scope ????
        return planet.$star.load(on: req.db) // returns a EventLoopFuture<Void>
    }
    .map {
      // I know that star has been loaded but I lost my `planet` reference ☹️
      ???
    }

我假设有一个运算符应该能够返回 2 个 EventLoopFuture 实例的混合,但我想不通。

问题 #2。将 EventLoopFuture 与辅助 HTTP 请求的响应链接起来

同样,我假设我错过了一个运算符,它允许我在响应原始请求之前等待请求的响应,同时保留对行星的引用。


欢迎提供有关如何通过良好的操作链实现这一点的帮助——当然,如果可能的话——我将非常乐意相应地更新 Vapor 的文档。 ????

【问题讨论】:

    标签: swift vapor


    【解决方案1】:

    简而言之,如果你需要一个未来的结果在另一个未来的结果中,那么你必须嵌套回调——你不能使用链接。比如:

    Planet(req.parameters.get("planetID"), on: req.db)
        .unwrap(or: Abort(.notFound))
        .flatMap { planet in // planet is in the scope ?
            return planet.$star.load(on: req.db).map {
                // Star is now eager loaded and you have access to planet
            }
        }
    

    如果您有多个彼此不依赖的期货,但您需要两者的结果,您可以使用and 将两者链接在一起并等待它们。例如:

    func flagPlanetAsHumanFriendly(req: Request) throws -> EventLoopFuture<Planet> {
        Planet(req.parameters.get("planetID"), on: req.db)
            .unwrap(or: Abort(.notFound))
            .flatMap { planet in
                // I load the star because I need its ID for the HTTP callback
                planet.$star.load(on: req.db).map {
                    let uri = URI(scheme: "http", host: "localhost", port: 4200, path: "/webhooks/star")
                    // HTTP Callback
                    let postFuture = req.client.post(uri) { req in
                        try req.content.encode(
                            WebhookDTO(
                                starId: planet.star.id!,
                                status: .humanFriendly,
                                planetId: planet.id!
                            ),
                            using: JSONEncoder()
                        )
                    }.map { res in
                        debugPrint("\(res)")
                        return
                    }
    
                    planet.state = .humanFriendly
                    let planetUpdateFuture = planet.save(on: req.db)
    
                    return postFuture.and(planetUpdateFuture).flatMap { _, _ in
                        return planet
                    }
                }
            }
    }
    

    【讨论】:

    • 感谢@0xTim 的友好回答。从假期回来,并准备摇滚这个解决方案。 ?
    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 2021-01-23
    • 2014-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    相关资源
    最近更新 更多