ann*_*rns 11 rest ios siesta swift siesta-swift
我想使用ResponseTransformer(或其中一系列)自动将我的对象模型类映射到从Siesta服务返回的响应,以便我的Siesta资源是我的模型类的实例.我有一个类的工作实现,但我想知道在为每种类型的资源(模型)构建单独的ResponseTransformer之前是否有更安全,更智能或更有效的方法.
这是一个示例模型类:
import SwiftyJSON
class Challenge {
var id:String?
var name:String?
init(fromDictionary:JSON) {
if let challengeId = fromDictionary["id"].int {
self.id = String(challengeId)
}
self.name = fromDictionary["name"].string
}
}
extension Challenge {
class func parseChallengeList(fromJSON:JSON) -> [Challenge] {
var list = [Challenge]()
switch fromJSON.type {
case .Array:
for itemDictionary in fromJSON.array! {
let item = Challenge(fromDictionary: itemDictionary)
list.append(item)
}
case .Dictionary:
list.append(Challenge(fromDictionary: fromJSON))
default: break
}
return list
}
}
Run Code Online (Sandbox Code Playgroud)
这里是我构建的ResponseTransformer,用于映射来自任何端点的响应,该端点返回此模型类型的集合或此模型类型的单个实例:
public func ChallengeListTransformer(transformErrors: Bool = true) -> ResponseTransformer {
return ResponseContentTransformer(transformErrors: transformErrors)
{
(content: NSJSONConvertible, entity: Entity) throws -> [Challenge] in
let itemJSON = JSON(content)
return Challenge.parseChallengeList(itemJSON)
}
}
Run Code Online (Sandbox Code Playgroud)
最后,这是我在配置Siesta服务时正在进行的URL模式映射:
class _GFSFAPI: Service {
...
configure("/Challenge/*") { $0.config.responseTransformers.add(ChallengeListTransformer()) }
}
Run Code Online (Sandbox Code Playgroud)
我打算为每个模型类型构建一个单独的ResponseTransformer,然后将每个URL模式单独映射到该变换器.这是最好的方法吗?顺便说一句,我对新的Siesta框架感到非常兴奋.我喜欢面向资源的REST网络库的想法.
你的方法很扎实!你基本上得到了它.您可以采取一些措施来简化变压器.
听起来你已经掌握了这种权衡,但对于那些找到这个答案的人来说......你有两种一般的方法可供选择:
选项1更容易设置 - 只需在现场制作模型,您就完成了!
func resourceChanged(resource: Resource, event: ResourceEvent) {
let challenges = Challenge.parseChallengeList(
JSON(resource.latestData?.jsonDict))
...
}
Run Code Online (Sandbox Code Playgroud)
这适用于许多项目.但它有缺点:
如果(并且仅当)项目很小并且模型是轻量级的,我更喜欢选项1.
您可以在用户指南的Pipeline部分找到有关选项2的大量文档.这是一个快速概述.
configureTransformer
您可以ChallengeListTransformer
使用configureTransformer(...)
以下方式简化您:
configureTransformer("/Challenge/*") {
(content: NSJSONConvertible, entity: Entity) throws -> [Challenge] in
let itemJSON = JSON(content)
return Challenge.parseChallengeList(itemJSON)
}
Run Code Online (Sandbox Code Playgroud)
但等等,还有更多!观看Swift的惊人类型推理切片和骰子:
configureTransformer("/Challenge/*") {
Challenge.parseChallengeList(
JSON($0.content as NSJSONConvertible))
}
Run Code Online (Sandbox Code Playgroud)
(注意configureTransformer
设置transformErrors
为false.这几乎可以肯定你想要的...除非你的服务器发送一个JSON"挑战"模型作为错误响应的主体!该transformErrors
选项通常只适用于文本和JSON解析等通用变换器与内容类型相关联,而不是与路由相关联的内容类型.)
如果您正在使用SwiftyJSON(我也喜欢BTW),那么您可以将它集中应用于所有JSON响应:
private let SwiftyJSONTransformer =
ResponseContentTransformer(skipWhenEntityMatchesOutputType: false)
{ JSON($0.content as AnyObject) }
Run Code Online (Sandbox Code Playgroud)
…然后:
service.configure {
$0.config.responseTransformers.add(
SwiftyJSONTransformer, contentTypes: ["*/json"])
}
Run Code Online (Sandbox Code Playgroud)
...进一步简化了每个路由的内容转换器:
configureTransformer("/Challenge/*") {
Challenge.parseChallengeList($0.content)
}
Run Code Online (Sandbox Code Playgroud)
请注意,Swift的类型推断告诉Siesta,这个变换器需要一个JSON
struct作为输入,而Siesta使用它来将它标记为错误,如果它没有以这种方式从变换器管道中出来的话.与JSON相关的转换器都附加到*/json
内容类型,因此如果服务器返回任何意外的内容,您的观察者会看到一个漂亮整洁的"嘿,那不是JSON!"错误.
正如Siesta API目前所示,您需要向下转换模型的内容:
func resourceChanged(resource: Resource, event: ResourceEvent) {
let challenges = resource.latestData?.content as? [Challenge]
...
}
Run Code Online (Sandbox Code Playgroud)
或者,TypedContentAccessors
如果数据尚未存在或者转换失败,您可以使用协议扩展方法同时执行转换并获取默认值.例如,如果没有挑战,此代码默认为空数组:
func resourceChanged(resource: Resource, event: ResourceEvent) {
let challenges = resource.typedContent(ifNone: [Challenge]())
...
}
Run Code Online (Sandbox Code Playgroud)
Siesta目前不提供将模型类型绑定到资源的静态类型方式; 你必须做演员.这是因为Swift类型系统的限制阻止了通用资源类型(例如Resource<[Challenge]>
)在实践中可行的东西.希望Swift 3解决这些问题,以便Siesta的未来版本可以提供这些.更新:对Swift 3进行了必要的泛型改进,所以希望在Swift 4 ......中.
归档时间: |
|
查看次数: |
1529 次 |
最近记录: |