控制器帮助您将相关的功能组织到一个地方。它们还可以用于创建RESTful资源。
基本(Basic)
一个基本的控制器看起来像下面这样:
import Vapor
import HTTP
final class HelloController {
func sayHello(_ req: Request) throws -> ResponseRepresentable {
guard let name = req.data["name"]?.string else {
throw Abort(.badRequest)
}
return "Hello, \(name)"
}
}
简单的控制器不需要遵守任何协议。你可以自由地设计它们,只要你认为合适。
注册(Registering)
唯一需要的结构是控制器中每个方法的签名。为了将这个方法注册到路由器中,它必须有一个签名,(Request) throws -> ResponseRepresentable
。通过导入HTTP
模块,可以获得请求(Request
)和响应(ResponseRepresentable
)。
import Vapor
let drop = try Droplet()
let hc = HelloController()
drop.get("hello", handler: hc.sayHello)
由于sayHello
”方法的签名与drop.get
方法的闭包签名相匹配,我们可以直接传递它。
类型安全(Type Safe)
您还可以使用带有类型安全路由的控制器方法。
final class HelloController {
...
func sayHelloAlternate(_ req: Request) -> ResponseRepresentable {
let name: String = try req.parameters.next(String.self)
return "Hello, \(name)"
}
}
我们在HelloController
中添加一个名为sayHelloAlternate
的新方法,从请求的参数中获取一个String
。
let hc = HelloController()
drop.get("hello", String.parameter, handler: hc.sayHelloAlternate)
由于dropget
接受了一个签名(Request) throws -> ResponseRepresentable
,我们的方法现在可以作为这条路线的终止。
笔记
在路由参数(Routing Parameters)部分阅读更多关于类型安全路由的信息。
资源(Resources)
符合ResourceRepresentable
的控制器可以很容易地作为一个RESTful资源被注册到路由器。让我们来看一个UserController
的例子。
final class UserController {
func index(_ req: Request) throws -> ResponseRepresentable {
return try User.all().makeJSON()
}
func show(_ req: Request) throws -> ResponseRepresentable {
let user = try req.parameters.next(User.self)
return user
}
}
这是一个典型的用户控制器,它有一个index
和show
路径。索引返回所有用户的JSON列表,并显示返回单个用户的JSON数据。
我们可以像这样注册控制器:
let users = UserController()
drop.get("users", handler: users.index)
drop.get("users", User.self, handler: users.show)
但是,ResourceRepresentable
使得这种标准的RESTful结构很容易。
extension UserController: ResourceRepresentable {
func makeResource() -> Resource<User> {
return Resource(
index: index,
show: show
)
}
}
符合ResourceRepresentable
的UserController
需要index
和show
方法的签名与Resource<User>
的期望相匹配。
现在,UserController
可以满足ResourceRepresentable
的需要,注册路由很容易。
let users = UserController()
drop.resource("users", users)
drop.resource
将只负责注册由调用makeResource()
所提供的路由。在这种情况下,只提供index
和show
路径。
Note
drop.resource
还为选择项(OPTIONS)请求增加了有用的缺省值。这些可以被重载。
行动(Actions)
下面是一个描述所有可用操作的表。
Action | Method | Path | Note |
---|---|---|---|
index | GET | /users | Returns all users, optionally filtered by the request data. |
store | POST | /users | Creates a new user from the request data. |
show | GET | /users/:id | Returns the user with the ID supplied in the path. |
replace | PUT | /users/:id | Updates the specified user, setting any fields not present in the request data to nil. |
update | PATCH | /users/:id | Updates the specified user, only modifying fields present in the request data. |
delete | DELETE | /users/:id | Deletes the specified user. |
clear | DELETE | /users | Deletes all users, optionally filtered by the request data. |
create | GET | /users/create | Displays a form for creating a new user. |
edit | GET | /users/:id/edit | Displays a form for editing the specified user. |
提示
replace
和update
之间的差异是很微妙但很重要的:如果请求数据中不存在某个字段(例如,用户的年龄丢失了),update
应该不会更新该字段,因为replace
应该将其设置为nil。如果replace
请求中缺少所需的数据,则应该抛出一个错误。
文件夹(Folder)
控制器可以在应用程序的任何地方进行,但它们通常存储在应用App/Controllers/
目录中。
提示
如果您正在构建一个大型应用程序,您可能希望在一个单独的模块中创建控制器。这将允许您在控制器上执行单元测试。