Vapor 3 Beta示例端点请求

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

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

我已经在其他地方看到了Vapor 2的例子,但它们与Vapor 3不再相关,目前的Vapor 3 beta文档还不清楚。

就像是...

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

}

}

swift server-side beta vapor
1个回答
18
投票

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

Futures

Future<Expectation>是围绕Expectation的包装纸。期望可能成功或失败(带有错误)。

Future类型可以注册成功完成时执行的回调。我们在这里使用的其中一个回调是flatMap。我们先来看看常规的map

如果你map一个未来你改变未来的成功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块将永远不会被触发,而AnyError条件将在catch块中找到。

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

flatMap与上面的例子非常相似。这是一个map,尾随封闭返回Future<Expectation>而不是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<Int>,因为递归期货将从Future<Future<Int>>扁平化到Future<Int>

Content

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

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

Logic

回到原来的路线:

  • 首先做一个客户
  • http://example.vapor.codes/json提出请求
  • 异步读取Future<Response>中的内容
  • 异步将结果渲染到视图中
  • 返回Future<View>

该框架将理解您将返回Future<View>并将继续处理其他请求而不是等待结果。

收到JSON后,此请求将再次被接收并处理为您的Web浏览器将收到的响应。

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

© www.soinside.com 2019 - 2024. All rights reserved.