我有一个用 Vapor 编写的 API。我想遵循 JSON API 规范。
我很难理解如何以正确的格式创建我的响应对象。
例如,我希望我的回复结构如下...
{
"links": {
"self": "http://example.com/dish",
"next": "http://example.com/dish?page=2",
"last": "http://example.com/dish?page=10"
},
"data": [{
"title": "Spag Bol",
"course": "main",
"description": "BasGetti",
"price": 3.9900000000000002
},
{
"title": "Ice Cream",
"course": "desert",
"description": "Vanilla",
"price": 0.98999999999999999
}]
}
如果 POST 到这个端点(伪代码),我可以非常简单地返回数据的内容
router.post(Dish.self, at: "api/dish") { req, data -> Future<Dish> in
return Future.map(on: req, { () -> Dish in
data.id = 001
return data
})
}
我尝试创建一个 ApiResponse 类并传入数据,这样我就可以构建响应,但这并没有解决错误 Cannot convert return expression of type 'ApiResonse' to return type '菜'
router.post(Dish.self, at: "api/dish") { req, data -> Future<Dish> in
return Future.map(on: req, { () -> Dish in
data.id = 001
return ApiResonse(links: Links(self: "http://google.com", next: "http://google.com", last: "http://google.com"), data: data)
})
}
我不确定我该怎么做。这些是尝试过的类(class)
final class Dish: Content {
var id: Int?
var title: String
var description: String
var course: String
var price: Double
init(title: String, description: String, course: String, price: Double) {
self.title = title
self.description = description
self.course = course
self.price = price
}
}
struct Links {
var `self`: String?
var next: String?
var last: String?
}
class ApiResonse {
var links: Links?
var data: Any
init(links: Links, data: Any) {
self.links = links
self.data = data
}
}
我是否需要使用泛型来设置响应类?谁能举个例子?
最佳答案
每个 class或 struct在复合对象中 ApiResponse需要遵守 Content协议(protocol)。 Content协议(protocol)包括 Codable JSON解码和编码协议(protocol)。
注意 Any 不符合Codable协议(protocol),因此 Any 不能用作响应的任何组成部分。参见 Vapor 3 Docs: "Using Content"和 Vapor 4 Docs: "Content"获取更多详细信息。
Vapor 3: all content types (JSON, protobuf, URLEncodedForm, Multipart, etc) are treated the same. All you need to parse and serialize content is a
Codableclass or struct.
Vapor 4: Vapor's content API allows you to easily encode / decode
Codablestructs to / from HTTP messages.
完全符合 Content 的对象或复合对象可以用作 ResponseEncodable响应。
ApiResponse当每个路由端点解析为特定的 Content 时,模型可以是通用的协议(protocol)兼容类型。
带有以下代码的示例项目在 GitHub: VaporExamplesLab/Example-SO-VaporJsonResponse 上.
示例模型
struct Dish: Content {
var id: Int?
var title: String
var description: String
var course: String
var price: Double
init(id: Int? = nil, title: String, description: String, course: String, price: Double) {
self.id = id
self.title = title
self.description = description
self.course = course
self.price = price
}
}
struct Links: Content {
var current: String?
var next: String?
var last: String?
}
struct ApiResponse: Content {
var links: Links?
var dishes: [Dish]
init(links: Links, dishes: [Dish]) {
self.links = links
self.dishes = dishes
}
}
示例 POST : 返回 ApiResponse
router.post(Dish.self, at: "api/dish") {
(request: Request, dish: Dish) -> ApiResponse in
var dishMutable = dish
dishMutable.id = 001
var links = Links()
links.current = "http://example.com"
links.next = "http://example.com"
links.last = "http://example.com"
return ApiResponse(links: links, dishes: [dishMutable])
}
示例 POST : 返回 Future<ApiResponse>
router.post(Dish.self, at: "api/dish-future") {
(request: Request, dish: Dish) -> Future<ApiResponse> in
var dishMutable = dish
dishMutable.id = 002
var links = Links()
links.current = "http://example.com"
links.next = "http://example.com"
links.last = "http://example.com"
return Future.map(on: request, {
() -> ApiResponse in
return ApiResponse(links: links, dishes: [dishMutable])
})
}
收到 JSON 响应
上述代码的响应主体产生以下内容:
{
"links": {
"current": "http://example.com",
"next": "http://example.com",
"last": "http://example.com"
},
"dishes": [
{
"id": 1,
"title": "Aztec Salad",
"description": "Flavorful Southwestern ethos with sweet potatos and black beans.",
"course": "salad",
"price": 1.82
}
]
}
通用模型
struct ApiResponseGeneric<T> : Content where T: Content {
var links: Links?
var data: T
init(links: Links, data: T) {
self.links = links
self.data = data
}
}
具体路线端点
router.post(Dish.self, at: "api/dish-generic-future") {
(request: Request, dish: Dish) -> Future<ApiResponseGeneric<[Dish]>> in
var dishMutable = dish
dishMutable.id = 004
var links = Links()
links.current = "http://example.com"
links.next = "http://example.com"
links.last = "http://example.com"
return Future.map(on: request, {
() -> ApiResponseGeneric<[Dish]> in
return ApiResponseGeneric<[Dish]>(links: links, data: [dishMutable])
})
}
关于swift - 使 Vapor API 响应符合 JSON API 规范,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52232746/
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
我正在为毕业设计开发GEM,TravisCI构建不断失败。这是我在Travis上的链接:https://travis-ci.org/ricardobond/perpetuus/builds/8709218构建错误是:$bundleexecrakerakeaborted!Don'tknowhowtobuildtask'default'/home/travis/.rvm/gems/ruby-1.9.3-p448/bin/ruby_noexec_wrapper:14:in`eval'/home/travis/.rvm/gems/ruby-1.9.3-p448/bin/ruby_noexec_
我有一个哈希条目数组,并希望根据传递给函数的参数进行过滤。如果散列中有三个值,A、B和C,我想做类似的事情:data=[{A:'a1',B:'b1',C:'c1'},{A:'a1',B:'b2',C:'c1'},{A:'a1',B:'b2',C:'c2'},{A:'a2',B:'b1',C:'c1'},{A:'a2',B:'b2',C:'c1'}]data.find_all{|d|d[:A].include?params[:A]}.find_all{|d|d[:B].include?params[:B]}.find_all{|d|d[:C].include?params[:C]}找到所
我有一个大数组,我需要知道它的所有元素是否都能被2整除。我是这样做的,但是有点丑:_true=truearr.each{|e|(e%2).zero?||_true=false}if_true==true#...end如何在没有额外循环/赋值的情况下做到这一点? 最佳答案 这样就可以了。arr.all?(&:even?) 关于ruby-如何找出所有数组元素是否都符合某个条件?,我们在StackOverflow上找到一个类似的问题: https://stackov
我有几个跳过的规范。Pending:(Failureslistedhereareexpectedanddonotaffectyoursuite'sstatus)1)...#Notyetimplemented#./spec/requests/request_spec.rb:22如何抑制未决规范的输出? 最佳答案 您可以添加以下配置选项以从运行中过滤掉所有待处理的规范:RSpec.configuredo|config|config.filter_run_excludingskip:trueend此外,here是一个更详细的抑制输出的建议
我正在构建Rails应用程序并使用RSpec制定测试。我为我正在创建的名为current_link_to的方法编写了测试。此方法应该检查当前页面是否对应于我传递给它的路径,并将current类添加到生成的链接中,以防它匹配。这是规范:require"spec_helper"describeApplicationHelperdodescribe"#current_link_to"dolet(:name){"Products"}let(:path){products_path}let(:rendered){current_link_to(name,path)}context"whenthe
我试图在我的RubyonRails应用程序中调试一个极其缓慢的请求调用。我已设法根据自己的喜好优化Controller方法,Rails的日志告诉我它已在XX毫秒内完成操作(Completed200OKin5049ms(Views:34.9ms|ActiveRecord:76.3ms)).但是,在加载页面时,在浏览器中实际呈现任何内容之前打印此消息很长;最多约15秒的等待时间。Rackmini-profiler证实了这一点,告诉我GET操作(不计算完成Controller操作所花费的时间)花费了14秒左右。(分析器还确认Controller操作的执行时间约为5秒)。我可以接受Contro
tl;dr:跳到最后一段最近一直在尝试使用RSpec的requestspecs做一些更有针对性的测试。我的测试主要是这样的:通用cucumber功能规范,即用户转到带有评论的帖子,对评论点赞,作者获得积分modelspecs当模型实际上具有某些功能时,即User#upvote(comment)controllerspecs我在其中stub了大部分内容,只是试图确保代码按照我期望的方式运行viewspecs当View中有一些复杂的东西时,例如仅在用户尚未投票时呈现upvote链接,这些被stub为好吧问题是当我有一些导致错误的特定场景时,一切似乎都在我无法重现它的模型/View层中工作。
我想通过Sinatra应用程序代理远程文件。这需要将带有header的HTTP响应从远程源流式传输回客户端,但我不知道如何在Net::HTTP#提供的block内使用流式API时设置响应header获取响应。例如,这不会设置响应头:get'/file'dostreamdo|out|uri=URI("http://manuals.info.apple.com/en/ipad_user_guide.pdf")Net::HTTP.get_response(uri)do|file|headers'Content-Type'=>file.header['Content-Type']file.re