Vapor 2.0 - 控制器(Controllers)

前往 Vapor 2.0 - 文档目录

控制器帮助您将相关的功能组织到一个地方。它们还可以用于创建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
    }
}

这是一个典型的用户控制器,它有一个indexshow路径。索引返回所有用户的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 {
        return Resource(
            index: index,
            show: show
        )
    }
}

符合ResourceRepresentableUserController需要indexshow方法的签名与Resource的期望相匹配。

现在,UserController可以满足ResourceRepresentable的需要,注册路由很容易。

let users = UserController()
drop.resource("users", users)

drop.resource将只负责注册由调用makeResource()所提供的路由。在这种情况下,只提供indexshow路径。

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.

提示
replaceupdate之间的差异是很微妙但很重要的:如果请求数据中不存在某个字段(例如,用户的年龄丢失了),update应该不会更新该字段,因为replace应该将其设置为nil。如果replace请求中缺少所需的数据,则应该抛出一个错误。

文件夹(Folder)

控制器可以在应用程序的任何地方进行,但它们通常存储在应用App/Controllers/目录中。

提示
如果您正在构建一个大型应用程序,您可能希望在一个单独的模块中创建控制器。这将允许您在控制器上执行单元测试。

你可能感兴趣的:(Vapor 2.0 - 控制器(Controllers))