-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Date decoding in URL query parameters #2481
Comments
I think for URL encoded parameters the default date decoding strategy is let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
ContentConfiguration.global.use(decoder: decoder, for: .urlEncodedForm) See: https://docs.vapor.codes/4.0/content/#override-defaults |
Thanks @avario for your answer. Unfortunately, I didn't manage to make it work. I set the content configuration in the |
@letatas Sorry, it should look like this for what you want: let decoder = URLEncodedFormDecoder(configuration: .init(dateDecodingStrategy: .iso8601))
ContentConfiguration.global.use(urlDecoder: decoder) |
According to Swift, the date you're passing is invalid. As an example using an example struct Example: Codable {
let date: Date
} First we'll try to decode the time string you provide. let input = "{\"date\": \"2020-08-18T12:00:00\"}".data(using: .utf8)!
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let e = try decoder.decode(Example.self, from: input)
print(e)
} catch {
print(error)
} You can see how the JSON object is created. This will always print an error.
So clearly, Swift doesn't understand what you're providing. So, what is it Swift does expect. Well, let's try the other way around. let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = formatter.date(from: "2020-08-18T12:00:00")!
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
do {
let e = Example(date: date)
let output = try encoder.encode(e)
} catch {
print(error)
} If we were to print output as
This might seem a bit odd, but I'm in a different time zone, which is automatically adjusted. This does however show your problem, you're missing the So fixing your issue, replace the time you're providing with extension JSONDecoder.DateDecodingStrategy {
/// The strategy that formats dates according to the ISO 8601 standard.
/// - Note: This includes the fractional seconds, unlike the standard `.iso8601`, which fails to decode those.
static var iso8601withFractionalSeconds: JSONDecoder.DateDecodingStrategy {
JSONDecoder.DateDecodingStrategy.custom { (decoder) in
let singleValue = try decoder.singleValueContainer()
let dateString = try singleValue.decode(String.self)
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
guard let date = formatter.date(from: dateString) else {
throw DecodingError.dataCorruptedError(in: singleValue, debugDescription: "Failed to decode string to ISO 8601 date.")
}
return date
}
}
} |
avario's answer is correct, but in case you need a custom decoder, then you can use the following: let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd"
// Date encoder for GET parameters
ContentConfiguration.global.use(urlDecoder: URLEncodedFormDecoder.createDateDecoder(formatter: f))
...
extension URLEncodedFormDecoder {
/** Creates decoder with custom date formatter
- Parameter formatter: the formatter
Example:
```
let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd"
// Date encoder for GET parameters
ContentConfiguration.global.use(urlDecoder: URLEncodedFormDecoder.createDateDecoder(formatter: f))
```
*/
static func createDateDecoder(formatter: DateFormatter) -> URLQueryDecoder {
let urlDecoder: URLQueryDecoder = URLEncodedFormDecoder(configuration: .init(dateDecodingStrategy: .custom({ (d: Decoder) -> Date in
let string = try d.singleValueContainer().decode(String.self)
if let date = formatter.date(from: string) {
return date
}
throw Abort(HTTPResponseStatus.badRequest)
})))
return urlDecoder
}
} |
Closing as the answer is #2481 (comment) |
Hello, I am trying to retrieve a date from a query parameter encoded in IS8601:
Unfortunately it seems that the
Date
in this format is not recognized.Steps to reproduce
Create a new project
vapor new date-issue
In the routes.swift add these lines :
Run the project, and in your terminal, call:
Expected behavior
I would expect
date
to benil
only when the parametersince
is absent or badly formatted. I expectdate
to contain the IS8601 decoded value of thesince
parameter.Actual behavior
Whatever the parameter
since
is populated or not,date
is alwaysnil
, even when a correctly encoded date is set.Environment
The text was updated successfully, but these errors were encountered: