@martijnwalraven
Server define a type 'Date', the format is '2017-06-06' or 1496736244000, (string or int).
Generate the scheme.json by apollo-codegen download-schema, the type is 'Date', too
Generate the API.swift by apollo-codegen generate , the type convert to 'String' automatically. Then data decode will throw exception when server format is int(1496736244000). Because it can not convert 'Int' to 'String'..
Now I have to change the API.swift manually, from 'String' to 'Int'. But it is not good, I have to do it many times when scheme changes...
Could you tell me the best way to solve the problem?
Thanks a lot
Jing
Did you find a solution for this? I'm also looking how to automatically create Date types during apollo codegen.
@cerupcat @jzhw0130: You should be able to pass --passthrough-custom-scalars to apollo-codegen to avoid generating a typealias to String for custom scalars. You can then add your own alias and conversion code, see here for an example.
Awesome, thanks! Will take a look.
@cerupcat I just modify the scheme.json manually to solve the problem
Thanks @jzhw0130. I don't think that would work for us since we share the schema file across platforms and it gets auto generated when we make changes. Will be giving the other solution a try when we get back to that part.
@jzhw0130 & @cerupcat Do you guys found a way to solve this?
I tried modifying the scheme.json file but it doesn't work.
Having trouble Decoding & Encoding DateTime type to Date in typealias.
Any help is appreciated.
I ran into a similar issue today and was able to find a solution.
Our schema had a custom scalar called Date. I wasn't able to make a type alias because Swift already obviously has type Date - plus, I wanted to convert the schema Date to Swift Date anyhow.
Here's what I did:
1) Add --passthroughCustomScalars to the build phase like below (see last line):
APOLLO_FRAMEWORK_PATH="$(eval find $FRAMEWORK_SEARCH_PATHS -name "Apollo.framework" -maxdepth 1)"
if [ -z "$APOLLO_FRAMEWORK_PATH" ]; then
echo "error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project."
exit 1
fi
cd "${SRCROOT}/${TARGET_NAME}"
$APOLLO_FRAMEWORK_PATH/check-and-run-apollo-cli.sh codegen:generate --queries="$(find . -name '*.graphql')" --passthroughCustomScalars --schema=schema.json API.swift
2) Add a Date extension like:
import Apollo
extension Date: JSONDecodable {
public init(jsonValue value: JSONValue) throws {
guard let isoString = value as? String else {
throw JSONDecodingError.couldNotConvert(value: value, to: Date.self)
}
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withFractionalSeconds]
guard let date = formatter.date(from: isoString) else {
throw JSONDecodingError.couldNotConvert(value: value, to: Date.self)
}
self = date
}
}
NOTE: Depending on the format of your ISO date string, you'll likely need to change formatter.formatOptions = [.withFractionalSeconds]. Our date strings have milliseconds, so I had to add these options for this to work.
Seeing people struggling with this, thought I will add my experience.
We have similar like @jzhw0130
Date format is '2017-06-06'
DateTime format is '2017-01-23T10:12:31Z' // ISO8601
Seconds format of 1496736244000 // Unix time stamp
and many other meaningless type like Markdown, VIDEO_ID etc that coming in string type
what we do is:
a) bash script to download and "transform" schema (with some comments):
# download new schema
apollo schema:download $SCHEMA_PATH --endpoint=$ENDPOINT_PATH
# strip down types we can't handle by representing them as strings
# (they are represented as strings in JSON)
perl -i -0pe 's/("kind":\s*"SCALAR",\s*"name":\s*")(Date|Markdown|VIDEO_ID)(")/\1String\3/gms' $SCHEMA_PATH
# Unix timestamp (Seconds) is represented as "TimeInterval" in iOS
# (in similar fashion you can "converting" your "Date" to "DateNoTime" if you want it to be typed in Swift)
perl -i -0pe 's/("kind":\s*"SCALAR",\s*"name":\s*")(Seconds)(")/\1TimeInterval\3/gms' $SCHEMA_PATH
b) Types.swift (in project)
public typealias DateTime = Date
extension DateTime: JSONDecodable, JSONEncodable {
public init(jsonValue value: JSONValue) throws {
guard let string = value as? String else {
throw JSONDecodingError.couldNotConvert(value: value, to: String.self)
}
guard let date = ISO8601DateFormatter().date(from: string) else {
throw JSONDecodingError.couldNotConvert(value: value, to: Date.self)
}
self = date
}
public var jsonValue: JSONValue {
return ISO8601DateTimeFormatter.string(from: self)
}
}
what this setup gives us is:
Date will be "String"
DateTime will be Swift "Date" (alias, decoded with our extension)
Seconds will be "TimeInterval" (decoded without any extension)
I've (finally) added some actual documentation and an example for this with #1474 - would appreciate any feedback.
Most helpful comment
Seeing people struggling with this, thought I will add my experience.
We have similar like @jzhw0130
Dateformat is '2017-06-06'DateTimeformat is '2017-01-23T10:12:31Z' // ISO8601Secondsformat of 1496736244000 // Unix time stampand many other meaningless type like
Markdown,VIDEO_IDetc that coming in string typewhat we do is:
a) bash script to download and "transform" schema (with some comments):
b)
Types.swift(in project)what this setup gives us is:
Datewill be "String"DateTimewill be Swift "Date" (alias, decoded with our extension)Secondswill be "TimeInterval" (decoded without any extension)