warning
本篇作为vapor文档基础篇,读起来很无聊,很漫长,很空洞。为了后面的vapor生活,务必认真学习。(认真脸)
前言
上一篇我们初步了解了vapor在Heroku上的部署,本篇我们一起来开始学习vapor官方文档中的Droplet和Route。划重点啊,同学们!因为本人也是初学,所有难免出现错误,大虾们多多指正。
Droplet
Droplet是一个服务容器,可以让你访问许多Vapor的服务。它负责注册路由,启动服务器,中间件 (middleware)等等。
通常我们在main.swift里创建Droplet
import Vapor
let drop = try Droplet()
// your magic here
try drop.run()
更多操作参考文档
Route(路由)
注册
注册一个最基本的路由通过对全局Droplet对象调用一个方法,指定路径和一个闭包来接收操作处理。
drop.get("hello") { request in
return "Hello"
}
通过调用get()
方法来注册了一个路径为/hello
的路由,并返回了"Hello"
这个字符串到浏览器,当然我们除了get
还可以其他的标准HTTP方法,比如 post、 put、 patch、 delete、options。
使用add()
方法来注册路由,以接收第一个参数Method
作为HTTP方法来动态注册路由,Method
是一个枚举,包含了上述所列的HTTP标准方法.这个方法可以动态注册,并且支持一些其他不常见的方法(比如 trace)
drop.add(.trace, "welcome") { request in
return "Hello"
}
多级路径
关于多级路径的写法,可以直接使用/
,官方推荐“直接使用参数分割”这种写法,因为可以更容易写出类型安全的路由参数。
drop.get("foo/bar/baz") { request in
return "You requested /foo/bar/baz"
}
// recommend
drop.get("foo", "bar", "baz") { request in
return "You requested /foo/bar/baz"
}
通配符
关于URL路由中使用通配符
app.get("anything", "*") { request in
return "Matches anything after /anything"
}
像这个例子因为用了*
尾随参数,可以匹配到如下所有路径:
- /anything
- /anything/foo
- /anything/foo/bar
- /anything/foo/bar/baz
- ...
路由参数
Vapor提倡使用类型安全的路由参数来接收数据,在路由方法中使用Swift类型来指定参数类型,Vapor会在内部解析并将参数返回给闭包以供使用。
drop.get("users", Int.parameter) { req in
let userId = try req.parameters.next(Int.self)
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)"
}
可以实现Parameterizable
协议来自定义参数类型。
请求
每个请求都会返回一个路由闭包,闭包里包含被调用的请求相关的所有数据。每个路由的闭包中可以返回三种类型的内容,Response、ResponseRepresentable、throw,我们可以返回自己所需的HTTP状态码、URL重定向、JSON等,基本涵盖日常所需的请求返回。
- Response
Response是Vapor中HTTP
模块中定义的基于Message
的类,有很多构造方法方便我们自定义 response 返回:
// 重定向
Response(redirect: "http://vapor.codes")
// JSON
Response(status: .ok, json: JSON(["hello":"world"]))
// String
Response(body: "hello")
- ResponseRepresentable
ResponseRepresentable
是一个协议,任何遵循这个协议的对象均可在路由中返回。如vapor中的JSON
、Model
对象。
- throw
我们可以抛出任何遵从Swift.Error
协议的对象,Vapor中自带默认error枚举Abort
。
drop.get("error") { request in
throw Abort(.badRequest, reason: "Sorry 😱")
}
路由组
Vapor提供了路由组的概念,通常用来集中组织一组相同前缀,添加中间件,限制主机名,或者集中管理的路由,路由组有两个类型:Group
和Grouped
。
Group通过一个闭包(RouteBuilder
)来收纳旗下所有的路由
drop.group("v1") { v1 in
v1.get("users") { request in
// get the users
}
}
Grouped会返回一个可以传递的RouteBuilder
。
let v1 = drop.grouped("v1")
v1.get("users") { request in
// get the users
}
中间件
我们可以将中间件添加到一组路由。 这对于身份验证特别有用。
drop.group(AuthMiddleware()) { authorized in
authorized.get("token") { request in
// has been authorized
}
}
Host
限制一组路由的host。
drop.group(host: "vapor.codes") { vapor in
vapor.get { request in
// only responds to requests to vapor.codes
}
}
链式调用
路由组可以链式调用。
drop.grouped(host: "vapor.codes").grouped(AuthMiddleware()).group("v1") { authedSecureV1 in
// add routes here
}
路由集合
路由集合允许将多个路由和路由组组织到不同的文件或模块中。
例如:
遵守RouteCollection
import Vapor
import HTTP
import Routing
class V1Collection: RouteCollection {
func build(_ builder: RouteBuilder) {
let v1 = builder.grouped("v1")
let users = v1.grouped("users")
let articles = v1.grouped("articles")
users.get { request in
return "Requested all users."
}
articles.get(Article.init) { request, article in
return "Requested \(article.name)"
}
}
}
我们在注册路由时直接添加到drop中即可。
let v1 = V1Collection()
drop.collection(v1)
遵守EmptyInitializable
协议。
class V1Collection: RouteCollection, EmptyInitializable {
init() { }
...
}
这时候添加到drop时可以不用实例化。
drop.collection(V1Collection.self)
最后
本篇基本是官方文档的粗略翻译版本,读起来比较空洞,下一篇我们结合简单的项目代码和固定套路,来从零开始vapor的异世界生活。