En mi aplicación Vapor 3, tengo un modelo de Event , que tiene las propiedades startDate: Date y endDate: Date .
Ahora, me pregunto cómo pasar esos valores de fecha en una solicitud POST. En Postman, probé lo siguiente en x-www-form-urlencoded :
startDate -> 2019-03-14Esto devuelve el siguiente error:
No se pudo convertir a
Double: str(\"2019-03-14\")
Aparentemente, Date se convierte en Double .
Entonces, en cambio, ¿qué valor necesito pasar?
Sé que, en Postman, puedo insertar {{$timestamp}} , pero 1) esto no responde a mi pregunta cuando uso la API fuera de Postman y 2) esto no me permite ingresar una fecha que no sea ahora .
Entonces, el problema aquí es que, de manera predeterminada, una instancia de Date se decodifica usando el intervalo de tiempo desde el 1 de enero de 2001. El decodificador de formulario de URL que usa Vapor no admite diferentes estrategias de fecha como lo hace JSONDecoder en este momento, por lo que deberá tienes que hacer la decodificación de una manera diferente. Aquí hay un par de ideas que se me podrían ocurrir:
Implemente manualmente los Event.init(from:) y .encode(to:) . Solo para asegurarse de no romper la codificación de Fluent, probablemente tendrá que agregar algo de lógica adicional, pero debería funcionar. Aquí hay un ejemplo:
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) } } }No estoy seguro acerca x-www-form-urlencoded porque lo probé y si envío una fecha como 0 , lo decodifica como 2001-01-01 00:00:00 +0000 , pensé que definitivamente debería ser 1970-01-01 00:00:00 +0000 .
Pero con la carga útil de JSON, tiene flexibilidad porque puede proporcionar un JSONDecoder configurado según sea necesario para usted.
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) } } Entonces, para la marca de tiempo de Unix, debe enviar segundos desde 1970 y, por ejemplo, 0 se decodificará a 1970-01-01 00:00:00 +0000 .
Y para el formato personalizado descrito anteriormente, debe enviar fechas como 2018-01-01 00:00:00 para decodificarlo como 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) } }entonces podrás decodificar tu carga útil de esta manera
router.post("check") { (req) throws -> Future<String> in return try req.content.decodeJson(Payload.self).map { p in return String(describing: p.date) } }Me di cuenta de que el objeto Date se devuelve en el siguiente formato cuando se consulta:
2021-12-31T14:29:00Z¡Así que esto es lo que traté de pasar y funcionó! No hay necesidad de decodificación personalizada.