Skip to content

Commit 015ae3c

Browse files
gh-action-runnergh-action-runner
authored andcommitted
Squashed 'apollo-ios/' changes from 52c5a41b..d82b2305
d82b2305 feature: Enhanced Client Awareness (#638) git-subtree-dir: apollo-ios git-subtree-split: d82b2305173ac6dd5a059595bfdcb07b9163c58e
1 parent f4752e1 commit 015ae3c

File tree

8 files changed

+156
-60
lines changed

8 files changed

+156
-60
lines changed

Sources/Apollo/ApolloClient.swift

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class ApolloClient {
3434

3535
public let store: ApolloStore
3636

37+
private let sendEnhancedClientAwareness: Bool
38+
3739
public enum ApolloClientError: Error, LocalizedError, Hashable {
3840
case noUploadTransport
3941

@@ -49,22 +51,40 @@ public class ApolloClient {
4951
///
5052
/// - Parameters:
5153
/// - networkTransport: A network transport used to send operations to a server.
52-
/// - store: A store used as a local cache. Note that if the `NetworkTransport` or any of its dependencies takes a store, you should make sure the same store is passed here so that it can be cleared properly.
53-
public init(networkTransport: any NetworkTransport, store: ApolloStore) {
54+
/// - store: A store used as a local cache. Note that if the `NetworkTransport` or any of its dependencies takes
55+
/// a store, you should make sure the same store is passed here so that it can be cleared properly.
56+
/// - sendEnhancedClientAwareness: Specifies whether client library metadata is sent in each request `extensions`
57+
/// key. Client library metadata is the Apollo iOS library name and version. Defaults to `true`.
58+
public init(
59+
networkTransport: any NetworkTransport,
60+
store: ApolloStore,
61+
sendEnhancedClientAwareness: Bool = true
62+
) {
5463
self.networkTransport = networkTransport
5564
self.store = store
65+
self.sendEnhancedClientAwareness = sendEnhancedClientAwareness
5666
}
5767

5868
/// Creates a client with a `RequestChainNetworkTransport` connecting to the specified URL.
5969
///
6070
/// - Parameter url: The URL of a GraphQL server to connect to.
61-
public convenience init(url: URL) {
71+
public convenience init(
72+
url: URL,
73+
sendEnhancedClientAwareness: Bool = true
74+
) {
6275
let store = ApolloStore(cache: InMemoryNormalizedCache())
6376
let provider = DefaultInterceptorProvider(store: store)
64-
let transport = RequestChainNetworkTransport(interceptorProvider: provider,
65-
endpointURL: url)
66-
67-
self.init(networkTransport: transport, store: store)
77+
let transport = RequestChainNetworkTransport(
78+
interceptorProvider: provider,
79+
endpointURL: url,
80+
sendEnhancedClientAwareness: sendEnhancedClientAwareness
81+
)
82+
83+
self.init(
84+
networkTransport: transport,
85+
store: store,
86+
sendEnhancedClientAwareness: sendEnhancedClientAwareness
87+
)
6888
}
6989
}
7090

Sources/Apollo/Constants.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import Foundation
22

33
public enum Constants {
4-
public static let ApolloVersion: String = "1.20.0"
4+
public static let ApolloClientName = "apollo-ios"
5+
public static let ApolloClientVersion: String = "1.20.0"
6+
7+
@available(*, deprecated, renamed: "ApolloClientVersion")
8+
public static let ApolloVersion: String = ApolloClientVersion
59
}

Sources/Apollo/JSONRequest.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import ApolloAPI
55

66
/// A request which sends JSON related to a GraphQL operation.
77
open class JSONRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
8-
8+
99
public let requestBodyCreator: any RequestBodyCreator
10-
1110
public let autoPersistQueries: Bool
1211
public let useGETForQueries: Bool
1312
public let useGETForPersistedQueryRetry: Bool
13+
public let serializationFormat = JSONSerializationFormat.self
14+
15+
private let sendEnhancedClientAwareness: Bool
16+
1417
public var isPersistedQueryRetry = false {
1518
didSet {
1619
_body = nil
@@ -25,8 +28,6 @@ open class JSONRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
2528
return _body!
2629
}
2730

28-
public let serializationFormat = JSONSerializationFormat.self
29-
3031
/// Designated initializer
3132
///
3233
/// - Parameters:
@@ -54,12 +55,14 @@ open class JSONRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
5455
autoPersistQueries: Bool = false,
5556
useGETForQueries: Bool = false,
5657
useGETForPersistedQueryRetry: Bool = false,
57-
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator()
58+
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator(),
59+
sendEnhancedClientAwareness: Bool = true
5860
) {
5961
self.autoPersistQueries = autoPersistQueries
6062
self.useGETForQueries = useGETForQueries
6163
self.useGETForPersistedQueryRetry = useGETForPersistedQueryRetry
6264
self.requestBodyCreator = requestBodyCreator
65+
self.sendEnhancedClientAwareness = sendEnhancedClientAwareness
6366

6467
super.init(
6568
graphQLEndpoint: graphQLEndpoint,
@@ -120,6 +123,7 @@ open class JSONRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
120123
private func createBody() -> JSONEncodableDictionary {
121124
let sendQueryDocument: Bool
122125
let autoPersistQueries: Bool
126+
123127
switch Operation.operationType {
124128
case .query:
125129
if isPersistedQueryRetry {
@@ -142,12 +146,16 @@ open class JSONRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
142146
autoPersistQueries = false
143147
}
144148

145-
let body = self.requestBodyCreator.requestBody(
149+
var body = self.requestBodyCreator.requestBody(
146150
for: operation,
147151
sendQueryDocument: sendQueryDocument,
148152
autoPersistQuery: autoPersistQueries
149153
)
150-
154+
155+
if self.sendEnhancedClientAwareness {
156+
addEnhancedClientAwarenessExtension(to: &body)
157+
}
158+
151159
return body
152160
}
153161

Sources/Apollo/RequestChainNetworkTransport.swift

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,36 @@ open class RequestChainNetworkTransport: NetworkTransport {
4141
///
4242
/// Defaults to an ``ApolloRequestBodyCreator`` initialized with the default configuration.
4343
public var requestBodyCreator: any RequestBodyCreator
44-
44+
45+
private let sendEnhancedClientAwareness: Bool
46+
4547
/// Designated initializer
4648
///
4749
/// - Parameters:
4850
/// - interceptorProvider: The interceptor provider to use when constructing a request chain
4951
/// - endpointURL: The GraphQL endpoint URL to use
50-
/// - additionalHeaders: Any additional headers that should be automatically added to every request. Defaults to an empty dictionary.
51-
/// - autoPersistQueries: Pass `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. Defaults to `false`.
52-
/// - requestBodyCreator: The `RequestBodyCreator` object to use to build your `URLRequest`. Defaults to the provided `ApolloRequestBodyCreator` implementation.
53-
/// - useGETForQueries: Pass `true` if you want to use `GET` instead of `POST` for queries, for example to take advantage of a CDN. Defaults to `false`.
54-
/// - useGETForPersistedQueryRetry: Pass `true` to use `GET` instead of `POST` for a retry of a persisted query. Defaults to `false`.
55-
public init(interceptorProvider: any InterceptorProvider,
56-
endpointURL: URL,
57-
additionalHeaders: [String: String] = [:],
58-
autoPersistQueries: Bool = false,
59-
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator(),
60-
useGETForQueries: Bool = false,
61-
useGETForPersistedQueryRetry: Bool = false) {
52+
/// - additionalHeaders: Any additional headers that should be automatically added to every request. Defaults to
53+
/// an empty dictionary.
54+
/// - autoPersistQueries: Pass `true` if Automatic Persisted Queries should be used to send a query hash instead
55+
/// of the full query body by default. Defaults to `false`.
56+
/// - requestBodyCreator: The `RequestBodyCreator` object to use to build your `URLRequest`. Defaults to the
57+
/// provided `ApolloRequestBodyCreator` implementation.
58+
/// - useGETForQueries: Pass `true` if you want to use `GET` instead of `POST` for queries, for example to take
59+
/// advantage of a CDN. Defaults to `false`.
60+
/// - useGETForPersistedQueryRetry: Pass `true` to use `GET` instead of `POST` for a retry of a persisted query.
61+
/// Defaults to `false`.
62+
/// - sendEnhancedClientAwareness: Specifies whether client library metadata is sent in each request `extensions`
63+
/// key. Client library metadata is the Apollo iOS library name and version. Defaults to `true`.
64+
public init(
65+
interceptorProvider: any InterceptorProvider,
66+
endpointURL: URL,
67+
additionalHeaders: [String: String] = [:],
68+
autoPersistQueries: Bool = false,
69+
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator(),
70+
useGETForQueries: Bool = false,
71+
useGETForPersistedQueryRetry: Bool = false,
72+
sendEnhancedClientAwareness: Bool = true
73+
) {
6274
self.interceptorProvider = interceptorProvider
6375
self.endpointURL = endpointURL
6476

@@ -67,6 +79,7 @@ open class RequestChainNetworkTransport: NetworkTransport {
6779
self.requestBodyCreator = requestBodyCreator
6880
self.useGETForQueries = useGETForQueries
6981
self.useGETForPersistedQueryRetry = useGETForPersistedQueryRetry
82+
self.sendEnhancedClientAwareness = sendEnhancedClientAwareness
7083
}
7184

7285
/// Constructs a GraphQL request for the given operation.
@@ -97,7 +110,8 @@ open class RequestChainNetworkTransport: NetworkTransport {
97110
autoPersistQueries: self.autoPersistQueries,
98111
useGETForQueries: self.useGETForQueries,
99112
useGETForPersistedQueryRetry: self.useGETForPersistedQueryRetry,
100-
requestBodyCreator: self.requestBodyCreator
113+
requestBodyCreator: self.requestBodyCreator,
114+
sendEnhancedClientAwareness: self.sendEnhancedClientAwareness
101115
)
102116

103117
if Operation.operationType == .subscription {
@@ -169,16 +183,19 @@ extension RequestChainNetworkTransport: UploadingNetworkTransport {
169183
with files: [GraphQLFile],
170184
context: (any RequestContext)? = nil,
171185
manualBoundary: String? = nil) -> HTTPRequest<Operation> {
172-
173-
UploadRequest(graphQLEndpoint: self.endpointURL,
174-
operation: operation,
175-
clientName: self.clientName,
176-
clientVersion: self.clientVersion,
177-
additionalHeaders: self.additionalHeaders,
178-
files: files,
179-
manualBoundary: manualBoundary,
180-
context: context,
181-
requestBodyCreator: self.requestBodyCreator)
186+
187+
UploadRequest(
188+
graphQLEndpoint: self.endpointURL,
189+
operation: operation,
190+
clientName: self.clientName,
191+
clientVersion: self.clientVersion,
192+
additionalHeaders: self.additionalHeaders,
193+
files: files,
194+
manualBoundary: manualBoundary,
195+
context: context,
196+
requestBodyCreator: self.requestBodyCreator,
197+
sendEnhancedClientAwareness: self.sendEnhancedClientAwareness
198+
)
182199
}
183200

184201
public func upload<Operation: GraphQLOperation>(
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Foundation
2+
#if !COCOAPODS
3+
import ApolloAPI
4+
#endif
5+
6+
extension JSONRequest {
7+
/// Adds client metadata to the request body in the `extensions` key.
8+
///
9+
/// - Parameter body: The previously generated JSON body.
10+
func addEnhancedClientAwarenessExtension(to body: inout JSONEncodableDictionary) {
11+
_addEnhancedClientAwarenessExtension(to: &body)
12+
}
13+
}
14+
15+
extension UploadRequest {
16+
/// Adds client metadata to the request body in the `extensions` key.
17+
///
18+
/// - Parameter body: The previously generated JSON body.
19+
func addEnhancedClientAwarenessExtension(to body: inout JSONEncodableDictionary) {
20+
_addEnhancedClientAwarenessExtension(to: &body)
21+
}
22+
}
23+
24+
fileprivate func _addEnhancedClientAwarenessExtension(to body: inout JSONEncodableDictionary) {
25+
let clientLibraryMetadata: JSONEncodableDictionary = [
26+
"name": Constants.ApolloClientName,
27+
"version": Constants.ApolloClientVersion
28+
]
29+
30+
var extensions = body["extensions"] as? JSONEncodableDictionary ?? JSONEncodableDictionary()
31+
extensions["clientLibrary"] = clientLibraryMetadata
32+
33+
body["extensions"] = extensions
34+
}

Sources/Apollo/RequestContext.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ public protocol RequestContext {}
1313

1414
/// A request context specialization protocol that specifies options for configuring the timeout of a `URLRequest`.
1515
///
16-
/// A `RequestContext` object can conform to this protocol to provide a custom `requestTimeout` for an individual request.
17-
/// If the `RequestContext` for a request does not conform to this protocol, the default request timeout of `URLRequest` will be used.
16+
/// A `RequestContext` object can conform to this protocol to provide a custom `requestTimeout` for an individual
17+
/// request. If the `RequestContext` for a request does not conform to this protocol, the default request timeout
18+
/// of `URLRequest` will be used.
1819
public protocol RequestContextTimeoutConfigurable: RequestContext {
1920
/// The timeout interval specifies the limit on the idle interval allotted to a request in the process of
2021
/// loading. This timeout interval is measured in seconds.

Sources/Apollo/UploadRequest.swift

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ open class UploadRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
99
public let requestBodyCreator: any RequestBodyCreator
1010
public let files: [GraphQLFile]
1111
public let manualBoundary: String?
12-
1312
public let serializationFormat = JSONSerializationFormat.self
14-
13+
14+
private let sendEnhancedClientAwareness: Bool
15+
1516
/// Designated Initializer
1617
///
1718
/// - Parameters:
@@ -24,25 +25,32 @@ open class UploadRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
2425
/// - manualBoundary: [optional] A manual boundary to pass in. A default boundary will be used otherwise. Defaults to nil.
2526
/// - context: [optional] A context that is being passed through the request chain. Should default to `nil`.
2627
/// - requestBodyCreator: An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation.
27-
public init(graphQLEndpoint: URL,
28-
operation: Operation,
29-
clientName: String,
30-
clientVersion: String,
31-
additionalHeaders: [String: String] = [:],
32-
files: [GraphQLFile],
33-
manualBoundary: String? = nil,
34-
context: (any RequestContext)? = nil,
35-
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator()) {
28+
public init(
29+
graphQLEndpoint: URL,
30+
operation: Operation,
31+
clientName: String,
32+
clientVersion: String,
33+
additionalHeaders: [String: String] = [:],
34+
files: [GraphQLFile],
35+
manualBoundary: String? = nil,
36+
context: (any RequestContext)? = nil,
37+
requestBodyCreator: any RequestBodyCreator = ApolloRequestBodyCreator(),
38+
sendEnhancedClientAwareness: Bool = true
39+
) {
3640
self.requestBodyCreator = requestBodyCreator
3741
self.files = files
3842
self.manualBoundary = manualBoundary
39-
super.init(graphQLEndpoint: graphQLEndpoint,
40-
operation: operation,
41-
contentType: "multipart/form-data",
42-
clientName: clientName,
43-
clientVersion: clientVersion,
44-
additionalHeaders: additionalHeaders,
45-
context: context)
43+
self.sendEnhancedClientAwareness = sendEnhancedClientAwareness
44+
45+
super.init(
46+
graphQLEndpoint: graphQLEndpoint,
47+
operation: operation,
48+
contentType: "multipart/form-data",
49+
clientName: clientName,
50+
clientVersion: clientVersion,
51+
additionalHeaders: additionalHeaders,
52+
context: context
53+
)
4654
}
4755

4856
public override func toURLRequest() throws -> URLRequest {
@@ -88,6 +96,10 @@ open class UploadRequest<Operation: GraphQLOperation>: HTTPRequest<Operation> {
8896
}
8997
fields["variables"] = variables
9098

99+
if self.sendEnhancedClientAwareness {
100+
addEnhancedClientAwarenessExtension(to: &fields)
101+
}
102+
91103
let operationData = try serializationFormat.serialize(value: fields)
92104
formData.appendPart(data: operationData, name: "operations")
93105

scripts/get-version.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ directory=$(dirname "$0")
44
source "$directory/version-constants.sh"
55

66
constantsFile=$(cat "$directory/../$APOLLO_CONSTANTS_FILE")
7-
currentVersion=$(echo $constantsFile | sed 's/^.*ApolloVersion: String = "\([^"]*\).*/\1/')
7+
currentVersion=$(echo $constantsFile | sed 's/^.*ApolloClientVersion: String = "\([^"]*\).*/\1/')
88
echo $currentVersion

0 commit comments

Comments
 (0)