Vapor 3 Beta 示例端点请求 [英] Vapor 3 Beta Example Endpoint Request

查看:48
本文介绍了Vapor 3 Beta 示例端点请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to find a simple example of how inside a router a person would send a request to the vapor sample endpoint http://example.vapor.codes/json, receive a response and map it to a struct or class.

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

I've seen examples elsewhere for Vapor 2 but they are no longer relevant with Vapor 3 and the current Vapor 3 beta documentation isn't clear.

类似……

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

}

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

My goal is to go grab something off the endpoint, turn it into a struct or class and display it in a leaf view.

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

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

Here is my outline for how I think it is done but I don't understand how to handle the response and process into the struct so that I can use it in my home.leaf in its html (I'm not concerned with the leaf part assume I have all the configuration for all that and imports already).

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

}

}

推荐答案

示例代码

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

Example code

I strongly recommend you read the explaination below, but this is the code.

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

期货

A Future 是对 Expectation 的包装.期望可以成功或失败(带有错误).

Futures

A Future<Expectation> is a wrapper around the Expectation. The expectation can be successful or failed (with an Error).

Future 类型可以注册成功完成时执行的回调.我们在这里使用的这些回调之一是 flatMap.首先让我们深入研究一个常规的map.

The Future type can register callbacks which are executed on successful completion. One of these callbacks that we use here is flatMap. Let's dive into a regular map, first.

如果你map一个 Future,你就改变了 Future 成功的 Expectation 并透明地传递错误条件.

If you map a Future you transform the future's successful Expectation and transparently pass through error conditions.

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

If we complete the promise with a valid decimal integer formatted string like "4" it'll print integer: 4

promise.complete("4")

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

If we place any non-numeric characters in there like "abc" it'll throw an error inside the InvalidNumericString error which will be triggering the catch block.

promise.complete("abc")

无论您做什么,从 mapflatMap 函数抛出的错误都会通过其他转换透明地级联.转换未来只会转换 Expectation,并且仅在成功案例时触发.错误案例将从基本未来"复制到新转换的未来.

No matter what you do, an error thrown from a map or flatMap function will cascade transparently through other transformations. Transforming a future will transform the Expectation only, and only be triggered on successful cases. Error cases will be copied from the "base future" to the newly transformed future.

如果你没有完成承诺,而是让承诺失败,map 块将永远不会被触发,并且 AnyError 条件将在 catch改为块.

If instead of completing the promise you fail the promise, the map block will never be triggered and the AnyError condition will be found in the catch block instead.

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

flatMap 与上面的例子非常相似.这是一个 map,其中尾随闭包返回一个 Future 而不是 Expectation.

flatMap works very similarly to the above example. It's a map where the trailing closure returns a Future<Expectation> rather than Expectation.

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

So If we'd rewrite the map block to be a flatMap, although impractical, we'll end up with this:

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 因为递归期货将从 Future> 扁平化为未来.

intFuture is still a Future<Int> because the recursive futures will be flattened from Future<Future<Int>> to just Future<Int>.

response.content.decode 位读取 Content-Type 并查找此内容类型的默认 Decoder.解码后的结构体将作为 Future 返回,在这种情况下,该结构体是 ExampleData.

The response.content.decode bit reads the Content-Type and looks for the default Decoder for this Content Type. The decoded struct will then be returned as a Future<DecodedStruct>, in this case this struct is ExampleData.

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

The reason the content is returned asynchronously is because the content may not have completely arrived in the HTTP response yet. This is a necessary abstraction because we may be receiving files upwards of 100MB which could crash (cloud) servers with a small amount of memory available.

回到原来的路线:

  • 首先建立一个客户
  • http://example.vapor.codes/json
  • 发出请求
  • Future异步读取内容
  • 将结果异步渲染到视图中
  • 返回Future
  • First make a client
  • Make a request to http://example.vapor.codes/json
  • Read the content from the Future<Response> asynchronously
  • Render the results into the view asynchronously
  • Return the Future<View>

框架将理解您正在返回一个Future,并将继续处理其他请求,而不是等待结果.

The framework will understand that you're returning a Future<View> and will continue processing other requests rather than waiting on the results.

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

Once the JSON is received, this request will be picked up again and processed into a response which your web browser will receive.

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

Leaf is built on top of TemplateKit which will await the future asynchronously. Just like Vapor, Leaf and TemplateKit will understand Futures well enough that you can pass a Future instead of a struct (or vice versa) and they'll switch to anothe request until the future is completed, if necessary.

这篇关于Vapor 3 Beta 示例端点请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆