在我的Vapor 3应用程序中,我有一个Event
模型,它具有startDate: Date
和endDate: Date
属性。
现在,我想知道如何在POST请求中传递这些日期值。在Postman中,我在x-www-form-urlencoded
中尝试了以下内容:
startDate -> 2019-03-14
这将返回以下错误:
无法转换为
Double
:str(\“2019-03-14 \”)
显然,Date
变成了Double
。
那么,相反,我需要传递什么价值?
我知道,在邮递员中,我可以插入{{$timestamp}}
,但是1)在Postman之外使用API时这不回答我的问题2)这不允许我输入除现在以外的日期。
我不确定x-www-form-urlencoded
因为我测试了它,如果我发送日期作为0
它解码它2001-01-01 00:00:00 +0000
认为它肯定应该是1970-01-01 00:00:00 +0000
。
但是使用JSON有效负载,您可以提供灵活性,因为您可以根据需要提供配置的JSONDecoder
。
struct Payload: Content {
var date: Date
}
router.post("check") { req throws -> Future<String> in
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970 // choose it for unix-timestamp
return try req.content.decode(json: Payload.self, using: decoder).map { p in
return String(describing: p.date)
}
}
router.post("check") { req throws -> Future<String> in
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter) // custom date formatter
return try req.content.decode(json: Payload.self, using: decoder).map { p in
return String(describing: p.date)
}
}
因此,对于unix-timestamp,您应该从1970年开始发送秒数,例如0
将被解码为1970-01-01 00:00:00 +0000
。
对于上面描述的自定义格式,您应该发送像2018-01-01 00:00:00
这样的日期,将其解码为2018-01-01 00:00:00 +0000
extension ContentContainer where M: Request {
func decodeJson<D>(_ payload: D.Type) throws -> Future<D> where D: Decodable {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
return try decode(json: payload, using: decoder)
}
}
那么你就能像这样解码你的有效载荷
router.post("check") { (req) throws -> Future<String> in
return try req.content.decodeJson(Payload.self).map { p in
return String(describing: p.date)
}
}
所以这里的问题是默认情况下,使用自2001年1月1日以来的时间间隔对Date
实例进行解码.Vapor使用的URL form decoder不支持JSONDecoder
目前所做的不同日期策略,所以你必须以不同的方式进行解码。以下是我可以提出的一些想法:
Event.init(from:)
和.encode(to:)
方法。只是为了确保你不打破Fluent编码,你可能需要添加一些额外的逻辑,但它应该工作。这是一个例子:
final class Event: Model {
static let formDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
var startDate: Date
var endDate: Date
init(from decoder: Decoder)throws {
let container = try decoder.container(keyedby: CodingKeys.self)
if let start = try? container.decode(String.self, keyedBy: .startDate), let date = Event.formDateFormatter.string(from: start) {
self.startDate = date
} else {
self.startDate = try container.decode(Date.self, keyedBy: .startDate)
}
if let end = try? container.decode(String.self, keyedBy: .endDate), let date = Event.formDateFormatter.string(from: end) {
self.endDate = date
} else {
self.endDate = try container.decode(Date.self, keyedBy: .endDate)
}
}
}