EnvoyAmbassador 4.0.5

EnvoyAmbassador 4.0.5

测试已测试
语言 SwiftSwift
许可证 MIT
发布最后发布2018年10月
SPM支持 SPM

Fabien LegoupillotBecky ChristensenGreg LeeRobin Goos 维护。



Ambassador

Build Status CocoaPods Code Climate Issue Count GitHub license

基于 SWSGI 的 Swift 超轻量级 Web 框架

特性

  • 超轻量级
  • 易于使用,专为 UI 自动测试 API 模拟设计
  • 基于 SWSGI,除了 Embassy 外,还可以与 HTTP 服务器一起运行
  • 响应处理程序设计为中间件,易于组合
  • 兼容异步

示例

以下是使用 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"),
    ]
)