Routing Parameters
传统的Web
框架通过使用路由参数名称和类型的字符串为路由留出错误空间。vapor
利用Swift的关闭来提供更安全和更直观的访问路线参数的方法。
Type Safe
要创建一个类型安全的路由,只需用“类型”替换路径中的一部分。
drop.get("users", Int.self) { request, userId in
return "You requested User #\(userId)"
}
这将创建一个匹配的路径users/:id
,其中:id
是一个Int
类型。这是使用手动路由参数。
drop.get("users", ":id") { request in
guard let userId = request.parameters["id"]?.int else {
throw Abort.badRequest
}
return "You requested User #\(userId)"
}
在这里,可以看到类型安全路由保存~3行代码,并且还可以防止运行时错误,如拼写错误:id
。
String Initializable
任何符合的类型StringInitializable
都可以用作类型安全的路由参数。默认情况下,以下类型符合:
String
Int
Model
String
是最通用的,总是匹配。Int
只有当提供的字符串可以变成一个整数时才匹配。Model
仅当用作标识符的字符串可用于在数据库中查找模型时才匹配。
以前的user
例子可以进一步简化:
drop.get("users", User.self) { request, user in
return "You requested \(user.name)"
}
提供的标识符将自动用于查找用户。例如,如果/users/5
被请求,User
模型将被要求具有标识符的用户5
。如果找到,则请求成功并且调用关闭。如果没有,则抛出未找到的错误。
如果模型不符合StringInitializable
这将会怎么样?
drop.get("users", Int.self) { request, userId in
guard let user = try User.find(userId) else {
throw Abort.notFound
}
return "You requested User #\(userId)"
}
总而言之,类型安全路由可以从每个路由节省大约6行代码。
Protocol
创建符合StringInitializable
的类型是简单的:
public protocol StringInitializable {
init?(from string: String) throws
}
Here is what Model'
s conformance looks like for those who are curious.
extension Model {
public init?(from string: String) throws {
if let model = try Self.find(string) {
self = model
} else {
return nil
}
}
}
init
方法可以同时throw
和返回nil
。这允许throw
自己的错误。或者,如果想要默认的错误和行为,只需返回nil
。
Limits
类型安全路由目前仅限于三个路径部分。通常通过添加路由组来解决这个问题。
drop.group("v1", "users") { users in
users.get(User.self, "posts", Post.self) { request, user, post in
return "Requested \(post.name) for \(user.name)"
}
}
上述示例的结果路径是/v1/users/:userId/posts/:postId
Manual
如上所述,仍然可以自由地进行传统路由。这对于特别复杂的情况可能是有用的。
drop.get("v1", "users", ":userId", "posts", ":postId", "comments", ":commentId") { request in
let userId = try request.parameters.extract("userId") as Int
let postId = try request.parameters.extract("postId") as Int
let commentId = try request.parameters.extract("commentId") as Int
return "You requested comment #\(commentId) for post #\(postId) for user #\(userId)"
}
属性
request.parameters
用于提取在URI
路径中编码的参数(例如,/v1/users/1
具有:userId
等于的参数"1"
)。在参数作为查询的一部分被传递的情况下(例如/v1/search-user?userId=1
),就可以使用request.data
获取参数值(例如let userId = request.data["userId"]?.string
)。
请求参数可以作为字典访问,也可以使用 extract
抛出而不是返回可选的语法。
Groups
手动请求参数也适于组合
let userGroup = drop.grouped("users", ":userId")
userGroup.get("messages") { req in
let user = try req.parameters.extract("userId") as User
}
继续学习vapor学习教程-目录
网友评论