【问题标题】:Vapor 3 Beta Example Endpoint RequestVapor 3 Beta 示例端点请求
【发布时间】:2018-02-02 19:12:50
【问题描述】:

我试图找到一个简单的示例,说明一个人如何在路由器内部向蒸气样本端点http://example.vapor.codes/json 发送请求,接收响应并将其映射到结构或类。

我在其他地方看到过 Vapor 2 的示例,但它们不再与 Vapor 3 相关,而且当前的 Vapor 3 测试版文档还不清楚。

类似...

router.get("sample") { req in

  //1. create client
  //2. send get request to sample endpoint at http://example.vapor.codes/json
  //3. handle response and map to a struct or class

}

我的目标是从端点获取一些东西,将其转换为结构或类并在叶子视图中显示。

{"array":[0,1,2,3],"dict":{"lang":"Swift","name":"Vapor"},"number":123,"string":"test"}

这是我认为如何完成的大纲,但我不明白如何处理响应并处理到结构中,以便我可以在我的 home.leaf 的 html 中使用它(我不担心使用叶子部分假设我已经拥有所有配置并导入)。

router.get("example"){ req -> Future<View> in

    struct ExampleData: Codable {
        var array : [Int]
        var dict : [String : String]
    }

    return try req.make(Client.self).get("http://example.vapor.codes/json").flatMap(to: ExampleData.self) { res in
        //not sure what to do to set the values of the ExampleData
    }

    return try req.view().render("home", ExampleData())

}

}

【问题讨论】:

  • 这是相当宽泛的:“请在我的代码中填写整个空白”。究竟哪一部分,你不知道该怎么做?文档如何“不清楚”?
  • @matt 嗨,马特,我试图更新我的问题以更清楚。
  • 好问题@CoffeeAtBedtime。一个超级简单的例子真的会帮助 Tim 的 Ray Wenderlich 关于 Vapor 3 的书以及docs.vapor.codes/3.0/getting-started/async

标签: swift server-side beta vapor


【解决方案1】:

示例代码

强烈建议您阅读下面的说明,但这是代码。

struct ExampleData: Codable {
    var array : [Int]
    var dict : [String : String]
}

// Register a GET /example route
router.get("example") { req -> Future<View> in
    // Fetch an HTTP Client instance
    let client = try req.make(Client.self)

    // Send an HTTP Request to example.vapor.codes/json over plaintext HTTP
    // Returns `Future<Response>`
    let response = client.get("http://example.vapor.codes/json")

    // Transforms the `Future<Response>` to `Future<ExampleData>`
    let exampleData = response.flatMap(to: ExampleData.self) { response in
        return response.content.decode(ExampleData.self)
    }

    // Renders the `ExampleData` into a `View`
    return try req.view().render("home", exampleData)
}

期货

Future&lt;Expectation&gt;Expectation 的包装器。期望可以成功也可以失败(带有错误)。

Future 类型可以注册成功完成后执行的回调。我们在这里使用的这些回调之一是flatMap。让我们先来看看普通的map

如果你 map 一个 Future,你将转换未来的成功 Expectation 并透明地通过错误条件。

let promise = Promise<String>()
let stringFuture = promise.future // Future<String>
let intFuture = stringFuture.map(to: Int.self) { string -> Int in
    struct InvalidNumericString: Error {}

    guard let int = Int(string) else { throw InvalidNumericString() }

    return int // Int
}

intFuture.do { int in
    print("integer: ", int)
}.catch { error in
    print("error: \(error)")
}

如果我们使用有效的十进制整数格式的字符串(如"4")完成承诺,它将打印integer: 4

promise.complete("4")

如果我们在其中放置任何非数字字符,例如 "abc",它会在 InvalidNumericString 错误中抛出一个错误,这将触发 catch 块。

promise.complete("abc")

无论您做什么,mapflatMap 函数引发的错误都会通过其他转换透明地级联。转换未来只会转换Expectation,并且只会在成功的情况下触发。错误案例将从“基础未来”复制到新转换的未来。

如果你没有完成承诺而不是承诺失败,则永远不会触发 map 块,而是会在 catch 块中找到 AnyError 条件。

struct AnyError: Error {}
promise.fail(AnyError())

flatMap 的工作方式与上面的示例非常相似。这是一个map,其中尾随闭包返回Future&lt;Expectation&gt;,而不是Expectation

因此,如果我们将地图块重写为flatMap,虽然不切实际,但我们最终会得到这样的结果:

let intFuture = stringFuture.flatMap(to: Int.self) { string -> Future<Int> in
    struct InvalidNumericString: Error {}

    guard let int = Int(string) else { throw InvalidNumericString() }

    return Future(int) // Int
}

intFuture 仍然是 Future&lt;Int&gt;,因为递归期货将从 Future&lt;Future&lt;Int&gt;&gt; 扁平化为 Future&lt;Int&gt;

内容

response.content.decode 位读取 Content-Type 并查找此 Content Type 的默认 Decoder。解码后的结构体将返回为Future&lt;DecodedStruct&gt;,在本例中,该结构体为ExampleData

内容异步返回的原因是内容可能还没有完全到达HTTP响应中。这是一个必要的抽象,因为我们可能会接收超过 100MB 的文件,这可能会导致只有少量可用内存的(云)服务器崩溃。

逻辑

回到原来的路线:

  • 先做一个客户端
  • http://example.vapor.codes/json发出请求
  • Future&lt;Response&gt;异步读取内容
  • 将结果异步渲染到视图中
  • 返回Future&lt;View&gt;

框架将理解您正在返回 Future&lt;View&gt;,并将继续处理其他请求,而不是等待结果。

收到 JSON 后,将再次提取此请求并处理为您的网络浏览器将收到的响应。

Leaf 建立在 TemplateKit 之上,它将异步等待未来。就像 Vapor 一样,Leaf 和 TemplateKit 可以很好地理解 Futures,您可以传递 Future 而不是 struct(反之亦然),如果需要,它们会切换到另一个请求,直到 future 完成。

【讨论】:

  • 非常感谢,这正是我突破理解之墙所需要的,感谢您的全程解释。
  • 完美答案@JoannisO。我误解了步骤:将Future&lt;Response&gt; 转换为Future&lt;ExampleData&gt;,直到您的示例代码。
猜你喜欢
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
  • 1970-01-01
  • 2019-02-09
  • 2021-10-25
  • 1970-01-01
相关资源
最近更新 更多