-
Notifications
You must be signed in to change notification settings - Fork 730
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1474 from apollographql/custom-scalar-playground-…
…page Add minor docs + Custom Scalar playground page
- Loading branch information
Showing
11 changed files
with
226 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
Apollo.xcodeproj/xcshareddata/xcschemes/Apollo Playground.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
Apollo.xcodeproj/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
Apollo.xcodeproj/xcshareddata/xcschemes/ApolloWebSocket.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
208 changes: 208 additions & 0 deletions
208
...rounds/ApolloMacPlayground.playground/Pages/CustomScalars.xcplaygroundpage/Contents.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
//: [SQLite Cache](@previous) | ||
|
||
import Foundation | ||
import Apollo | ||
|
||
/*: | ||
## Custom Scalars | ||
Custom scalars allow you to define your own scalar types based on existing GraphQL scalar types. You can then use typealiasing and custom initializers to make these work with Swift types. | ||
To use these types in your code, you'll need to first make sure that when you generate code, `passthroughCustomScalars` is true, since otherwise you'll only get the underlying scalar types. | ||
The most common example is having your own date type. In this example, you'll take a type generated using `passthroughCustomScalars` called `CustomDate` and transform it into a `Foundation.Date` object you can use throughout your code. | ||
After generating the code using our code generation tooling, in a file **other than your API.swift file**, you will need to add a typealias to the underlying Swift type, so that Swift knows `CustomDate` is actually just a `Date` under the hood: | ||
*/ | ||
|
||
public typealias CustomDate = Foundation.Date | ||
|
||
/*: | ||
Next, add an extension that conforms that type to the `JSONDecodable` protocol, which takes in a raw value from JSON and then tries to create your underlying type: | ||
*/ | ||
|
||
extension CustomDate: JSONDecodable { | ||
|
||
public init(jsonValue value: JSONValue) throws { | ||
// Since you know the underlying scalar type of `CustomDate` is a String, you can pull the original string out. | ||
guard let string = value as? String else { | ||
throw JSONDecodingError.couldNotConvert(value: value, to: String.self) | ||
} | ||
|
||
// Next, if that worked, you parse the date using whatever formatter you want. In this case, since we know we're expecting an ISO8601 format, we can use the ISO8601 formatter. | ||
guard let date = ISO8601DateFormatter().date(from: string) else { | ||
throw JSONDecodingError.couldNotConvert(value: value, to: Date.self) | ||
} | ||
|
||
// Now that we've got a `Foundation.Date`, we can assign it here as `self` since `CustomDate` is typealiased to `Foundation.Date`. | ||
self = date | ||
} | ||
} | ||
|
||
/*: | ||
Again, for emphasis: **Do not** put these bits into a generated file, because they will get overwritten when you regenerate code. | ||
*/ | ||
|
||
/*: | ||
## A sample schema and query | ||
Here's a small sample schema we'll use to simulate the code generated here by our codegen tool: | ||
```graphql | ||
type DateInfo { | ||
date: CustomDate! | ||
} | ||
type Query { | ||
whatTimeIsIt: DateInfo! | ||
} | ||
``` | ||
Along with a small query to that schema: | ||
```graphql | ||
query CustomScalarDate { | ||
whatTimeIsIt { | ||
__typename | ||
date | ||
} | ||
} | ||
``` | ||
Below is the code that would be generated by this query against that schema (you can close it up by flipping the flippy triangle on line 77 if you don't want to look at it): | ||
*/ | ||
|
||
public final class CustomScalarDateQuery: GraphQLQuery { | ||
/// The raw GraphQL definition of this operation. | ||
public let operationDefinition: String = | ||
""" | ||
query CustomScalarDate { | ||
whatTimeIsIt { | ||
__typename | ||
date | ||
} | ||
} | ||
""" | ||
|
||
public let operationName: String = "CustomScalarDate" | ||
|
||
public let operationIdentifier: String? = "(not relevant here)" | ||
|
||
public init() { | ||
} | ||
|
||
public var variables: GraphQLMap? { | ||
return nil | ||
} | ||
|
||
public struct Data: GraphQLSelectionSet { | ||
public static let possibleTypes: [String] = ["Query"] | ||
|
||
public static var selections: [GraphQLSelection] { | ||
return [ | ||
GraphQLField("whatTimeIsIt", arguments: nil, type: .object(WhatTimeIsIt.selections)), | ||
] | ||
} | ||
|
||
public private(set) var resultMap: ResultMap | ||
|
||
public init(unsafeResultMap: ResultMap) { | ||
self.resultMap = unsafeResultMap | ||
} | ||
|
||
public init(whatTimeIsIt: WhatTimeIsIt? = nil) { | ||
self.init(unsafeResultMap: ["__typename": "Query", "whatTimeIsIt": whatTimeIsIt.flatMap { (value: WhatTimeIsIt) -> ResultMap in value.resultMap }]) | ||
} | ||
|
||
public var whatTimeIsIt: WhatTimeIsIt? { | ||
get { | ||
return (resultMap["whatTimeIsIt"] as? ResultMap).flatMap { WhatTimeIsIt(unsafeResultMap: $0) } | ||
} | ||
set { | ||
resultMap.updateValue(newValue?.resultMap, forKey: "whatTimeIsIt") | ||
} | ||
} | ||
|
||
public struct WhatTimeIsIt: GraphQLSelectionSet { | ||
public static var selections: [GraphQLSelection] { | ||
return [ | ||
GraphQLField("__typename", type: .nonNull(.scalar(String.self))), | ||
GraphQLField("date", type: .nonNull(.scalar(CustomDate.self))), | ||
] | ||
} | ||
|
||
public private(set) var resultMap: ResultMap | ||
|
||
public init(unsafeResultMap: ResultMap) { | ||
self.resultMap = unsafeResultMap | ||
} | ||
|
||
public var __typename: String { | ||
get { | ||
return resultMap["__typename"]! as! String | ||
} | ||
set { | ||
resultMap.updateValue(newValue, forKey: "__typename") | ||
} | ||
} | ||
|
||
public var date: CustomDate { | ||
get { | ||
return resultMap["date"]! as! CustomDate | ||
} | ||
set { | ||
resultMap.updateValue(newValue, forKey: "date") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/*: | ||
Next, we'll create the raw JSON that you'd receive in return, with the `CustomDate` type being a string that has an ISO8601-formatted date. | ||
*/ | ||
|
||
let json = | ||
""" | ||
{ | ||
"data": { | ||
"whatTimeIsIt": { | ||
"__typename": "DateInfo", | ||
"date": "2020-03-17T21:12:34Z" | ||
} | ||
} | ||
} | ||
""" | ||
|
||
/*: | ||
We'll turn this into the JSON that gets used by `GraphQLResponse`: | ||
*/ | ||
let data = json.data(using: .utf8)! | ||
|
||
let toJSON = try! JSONSerializationFormat.deserialize(data: data) | ||
let asObject = toJSON as! JSONObject | ||
|
||
let response: GraphQLResponse<CustomScalarDateQuery.Data> = GraphQLResponse(operation: CustomScalarDateQuery(), body: asObject) | ||
|
||
/*: | ||
Next, we'll turn that response into a result and try to get the date that was parsed: | ||
*/ | ||
let result = try! response.parseResultFast() | ||
|
||
guard let parsedDate = result.data?.whatTimeIsIt?.date else { | ||
fatalError("date did not parse correctly!") | ||
} | ||
|
||
/*: | ||
Finally, we'll use a date formatter set to UTC using the en-US locale, with short time style and long date style to print out the date. This should print out "March 17, 2020 at 9:12 PM". | ||
*/ | ||
|
||
let dateFormatter = DateFormatter() | ||
dateFormatter.locale = Locale(identifier: "en-US") | ||
dateFormatter.dateStyle = .long | ||
dateFormatter.timeStyle = .short | ||
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")! | ||
|
||
print(dateFormatter.string(from: parsedDate)) | ||
|
||
//: [Next](@next) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters