Параметр даты прохождения пара - PullRequest
1 голос
/ 15 марта 2019

В моем приложении Vapor 3 у меня есть модель Event, которая имеет свойства startDate: Date и endDate: Date.
Теперь мне интересно, как передать эти значения даты в запросе POST. В Почтальоне я попробовал следующее в x-www-form-urlencoded:

startDate -> 2019-03-14

Это возвращает ошибку ниже:

Не удалось преобразовать в Double: str (\ "2019-03-14 \")

Очевидно, Date превращается в Double.
Итак, какое значение мне нужно передать?


Примечание

Я знаю, что в Postman я могу вставить {{$timestamp}}, но 1) это не отвечает на мой вопрос при использовании API вне Postman и 2) это не позволяет мне вводить дату, отличную от сейчас .

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Таким образом, проблема заключается в том, что по умолчанию экземпляр Date декодируется с использованием временного интервала с 1 января 2001 года. Декодер формы URL *1003*, который использует Vapor, не поддерживает различные стратегии дат, такие как JSONDecoder делает в данный момент, поэтому вам придется выполнять декодирование другим способом. Вот несколько идей, которые я мог бы придумать:

  • Просто отправьте метку времени в запросе. Для тестирования разных дат в Postman вы можете установить переменную среды в скрипте предварительного запроса и получить к нему доступ в теле запроса.
  • Вручную реализовать методы 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)   
            }
        }
    }
    
1 голос
/ 15 марта 2019

Я не уверен насчет 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
}

Если вы хотите отправить даты в виде UNIX-отметки времени

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 вы должны отправить секунды с 1970 года и, например, 0 будет декодировано до 1970-01-01 00:00:00 +0000.

А для пользовательского формата, описанного выше, вы должны отправить даты вроде 2018-01-01 00:00:00, чтобы декодировать его как 2018-01-01 00:00:00 +0000

UPD: вы можете написать расширение, чтобы красиво его декодировать

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)
    }
}
...