Ambassador
基于 SWSGI 的 Swift 超轻量级 Web 框架
特性
示例
以下是使用 Ambassador 和作为 HTTP 服务器的 Embassy 来模拟 API 终端的示例。
import Embassy
import EnvoyAmbassador
let loop = try! SelectorEventLoop(selector: try! KqueueSelector())
let router = Router()
let server = DefaultHTTPServer(eventLoop: loop, port: 8080, app: router.app)
router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
return [
["id": "01", "name": "john"],
["id": "02", "name": "tom"]
]
}))
// Start HTTP server to listen on the port
try! server.start()
// Run event loop
loop.runForever()
然后您可以在浏览器中访问 http://[::1]:8080/api/v2/users,或者使用 HTTP 客户端获取该 URL 并查看。
[
{
"id" : "01",
"name" : "john"
},
{
"id" : "02",
"name" : "tom"
}
]
Router
Router
允许您将不同的路径映射到不同的 WebApp
。就像您在之前的例子中看到的那样,要将路径 /api/v2/users
路由到我们的响应处理程序,您只需用 WebApp
作为值设置所需的路径
let router = Router()
router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
return [
["id": "01", "name": "john"],
["id": "02", "name": "tom"]
]
}))
并将 router.app
作为 SWSGI 接口传递给 HTTP 服务器。当访问路径未找到时,将使用 router.notFoundResponse
,它简单地返回 404。您可以通过覆盖 notFoundResponse
来自定义未找到的行为。
您还可以使用正则表达式映射 URL。例如,您可以编写这个
let router = Router()
router["/api/v2/users/([0-9]+)"] = DelayResponse(JSONResponse(handler: { environ -> Any in
let captures = environ["ambassador.router_captures"] as! [String]
return ["id": captures[0], "name": "john"]
}))
然后,所有与 /api/v2/users/([0-9]+)
正则表达式匹配的请求都将路由到这里。对于所有匹配组,它们将以字符串数组的形式作为键 ambassador.router_captures
传递到环境变量中。
DataResponse
DataResponse
是用于发送数据的辅助工具。例如,如果您想创建一个端点返回状态代码 500,您可以这样做
router["/api/v2/return-error"] = DataResponse(statusCode: 500, statusMessage: "server error")
默认情况下,状态是 200 OK
,内容类型是 application/octet-stream
,它们都可以通过初始化参数来覆盖。您还可以提供自定义头和返回数据的处理程序。例如
router["/api/v2/xml"] = DataResponse(
statusCode: 201,
statusMessage: "created",
contentType: "application/xml",
headers: [("X-Foo-Bar", "My header")]
) { environ -> Data in
return Data("<xml>who uses xml nowadays?</xml>".utf8)
}
如果您希望以异步方式发送正文,您还可以使用带有额外 sendData
函数作为参数的另一个初始化项
router["/api/v2/xml"] = DataResponse(
statusCode: 201,
statusMessage: "created",
contentType: "application/xml",
headers: [("X-Foo-Bar", "My header")]
) { (environ, sendData) in
sendData(Data("<xml>who uses xml nowadays?</xml>".utf8))
}
请注意,与 SWSGI 的 sendBody
不同,sendData
只期望使用整个数据块调用一次。
JSONResponse
几乎与 DataResponse
相同,但它接收 Any
而不是字节,并以 JSON 格式转储对象并将其作为响应发送。例如
router["/api/v2/users"] = JSONResponse() { _ -> Any in
return [
["id": "01", "name": "john"],
["id": "02", "name": "tom"]
]
}
DelayResponse
DelayResponse
是一个 装饰器 响应,它将给定响应延迟一段时间。在现实世界中,网络延迟始终存在,为了模拟延迟,DelayResponse
非常有用。要延迟响应,只需这样做
router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
return [
["id": "01", "name": "john"],
["id": "02", "name": "tom"]
]
}))
默认情况下,它将随机延迟响应。您可以通过传递 delay
参数来修改它。例如,如果您想延迟 10 秒,那么您就这样做
router["/api/v2/users"] = DelayResponse(JSONResponse(handler: { _ -> Any in
return [
["id": "01", "name": "john"],
["id": "02", "name": "tom"]
]
}), delay: .delay(10))
可用的延迟选项有
- .random(min: 时间间隔, max: 时间间隔) 随机延迟,默认值为 .random(min: 0.1, max: 3)
- .delay(seconds: 时间间隔) 延迟指定的时间段
- .never 永久延迟,响应将永远不会返回
- .none 不延迟,即立即返回响应
DataReader
要从请求中读取POST正文或任何其他HTTP正文,您需要使用SWSGI参数中的environ
提供的swsgi.input
函数。例如,您可以这样做:
router["/api/v2/users"] = JSONResponse() { environ -> Any in
let input = environ["swsgi.input"] as! SWSGIInput
input { data in
// handle the data stream here
}
}
这样做并不困难,但是数据以流的形式到来,例如
- "第一块数据"
- "第二块数据"
- ....
- "" (空数据数组表示EOF)
在大多数情况下,您可能不会手动处理数据流。为了等待所有数据接收并一次性处理它们,您可以使用DataReader
。例如
router["/api/v2/users"] = JSONResponse() { environ -> Any in
let input = environ["swsgi.input"] as! SWSGIInput
DataReader.read(input) { data in
// handle the whole data here
}
}
JSONReader
与DataReader
类似,除了读取整个数据块,JSONReader
还会将其解析为JSON格式。以下是如何操作的:
router["/api/v2/users"] = JSONResponse() { environ -> Any in
let input = environ["swsgi.input"] as! SWSGIInput
JSONReader.read(input) { json in
// handle the json object here
}
}
URLParametersReader
URLParametersReader
等待所有数据接收并一次性将它们解析为URL编码参数,例如 foo=bar&eggs=spam
。参数将以数组键值对的形式作为(String, String)
传递。
router["/api/v2/users"] = JSONResponse() { environ -> Any in
let input = environ["swsgi.input"] as! SWSGIInput
URLParametersReader.read(input) { params in
// handle the params object here
}
}
如果您想解析URL编码的参数字符串,也可以使用URLParametersReader.parseURLParameters
。只需要这样做:
let params = URLParametersReader.parseURLParameters("foo=bar&eggs=spam")
安装
CocoaPods
使用CocoaPod安装,请在Podfile中添加Embassy
pod 'EnvoyAmbassador', '~> 4.0'
Carthage
使用Carthage安装,请在Cartfile中添加Ambassador
github "envoy/Ambassador" ~> 4.0
请注意,您应该导入Ambassador
而不是EnvoyAmbassador
。我们使用EnvoyAmbassador
是因为Ambassador
这个名字已经被使用了。
包管理器
为此,请将存储库添加到Package.swift
,如下所示
import PackageDescription
let package = Package(
name: "AmbassadorExample",
dependencies: [
.package(url: "https://github.com/envoy/Ambassador.git",
from: "4.0.0"),
]
)