Skip to content
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

Feature: Auto Persisted Queries with CDN Support #608

Closed
30 changes: 28 additions & 2 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
9FF90A731DDDEB420034C3B6 /* ParseQueryResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A6C1DDDEB420034C3B6 /* ParseQueryResponseTests.swift */; };
E86D8E05214B32FD0028EFE1 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86D8E03214B32DA0028EFE1 /* JSONTests.swift */; };
F16D083C21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F16D083B21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift */; };
F82E62E122BCD223000C311B /* AutomaticPersistedQueriesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */; };
F8AB781B22E1B4BB00A50B81 /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8AB781A22E1B4BB00A50B81 /* MockURLSession.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -363,6 +365,9 @@
9FF90A6C1DDDEB420034C3B6 /* ParseQueryResponseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseQueryResponseTests.swift; sourceTree = "<group>"; };
E86D8E03214B32DA0028EFE1 /* JSONTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONTests.swift; sourceTree = "<group>"; };
F16D083B21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryFromJSONBuildingTests.swift; sourceTree = "<group>"; };
F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutomaticPersistedQueriesTests.swift; sourceTree = "<group>"; };
F8AB781A22E1B4BB00A50B81 /* MockURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLSession.swift; sourceTree = "<group>"; };
F8E9D8AE22B2492C0065DA98 /* schema.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = schema.json; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -483,6 +488,7 @@
9F8A95811EC0FD3300304A2D /* XCTAssertHelpers.swift */,
9F8A95831EC0FD6100304A2D /* XCTestCase+Promise.swift */,
9F10A51D1EC1BA0F0045E62B /* MockNetworkTransport.swift */,
F8AB781A22E1B4BB00A50B81 /* MockURLSession.swift */,
9F8A95851EC0FD9800304A2D /* TestCacheProvider.swift */,
9F8A957A1EC0FC1200304A2D /* ApolloTestSupport.h */,
9F8A957B1EC0FC1200304A2D /* Info.plist */,
Expand Down Expand Up @@ -651,6 +657,7 @@
9FCE2CF41E6C20E000E34457 /* Tests */ = {
isa = PBXGroup;
children = (
F82E62DC22BCD1F2000C311B /* Apollo */,
9FC750521D2A532D00458D91 /* ApolloTests */,
9FA6ABBD1EC0A988000017BE /* ApolloCacheDependentTests */,
9FC631341E6AE2080062707E /* ApolloPerformanceTests */,
Expand Down Expand Up @@ -681,6 +688,7 @@
9FCE2D171E6C259B00E34457 /* Starship.graphql */,
9FCE2D0C1E6C259B00E34457 /* CreateReviewForEpisode.graphql */,
9FCE2D0A1E6C258A00E34457 /* API.swift */,
F8E9D8AE22B2492C0065DA98 /* schema.json */,
9FCE2CFC1E6C213D00E34457 /* StarWarsAPI.h */,
9FCE2CFD1E6C213D00E34457 /* Info.plist */,
);
Expand Down Expand Up @@ -711,6 +719,22 @@
name = "Supporting Files";
sourceTree = "<group>";
};
F82E62DC22BCD1F2000C311B /* Apollo */ = {
isa = PBXGroup;
children = (
F82E62DD22BCD1F2000C311B /* Network */,
);
path = Apollo;
sourceTree = "<group>";
};
F82E62DD22BCD1F2000C311B /* Network */ = {
isa = PBXGroup;
children = (
F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */,
);
path = Network;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -1038,7 +1062,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Do some magic so we can make sure `FRAMEWORK_SEARCH_PATHS` works correctly when there's a space in the scheme or the folder name.\nQUOTED_FRAMEWORK_SEARCH_PATHS=\\\"$(echo $FRAMEWORK_SEARCH_PATHS | tr -d '\"' | sed -e 's/ \\//\" \"\\//g')\\\"\n\n# Get the first result searching for the framework\nAPOLLO_FRAMEWORK_PATH=\"$(eval find ${QUOTED_FRAMEWORK_SEARCH_PATHS} -name \"Apollo.framework\" -maxdepth 1 -print | head -n 1)\"\n\nif [ -z \"${APOLLO_FRAMEWORK_PATH}\" ]; then\n echo \"error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project.\"\n exit 1\nfi\n\ncd ${SRCROOT}/Tests/GitHubAPI\nif [[ $SDK_NAME == *\"macos\"* ]]; then\n # Run the mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/Versions/Current/Resources/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nelse\n # Run the non-mac script\n\"${APOLLO_FRAMEWORK_PATH}\"/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nfi\n";
shellScript = "# Do some magic so we can make sure `FRAMEWORK_SEARCH_PATHS` works correctly when there's a space in the scheme or the folder name.\nQUOTED_FRAMEWORK_SEARCH_PATHS=\\\"$(echo $FRAMEWORK_SEARCH_PATHS | tr -d '\"' | sed -e 's/ \\//\" \"\\//g')\\\"\n\n# Get the first result searching for the framework\nAPOLLO_FRAMEWORK_PATH=\"$(eval find ${QUOTED_FRAMEWORK_SEARCH_PATHS} -name \"Apollo.framework\" -maxdepth 1 -print | head -n 1)\"\n\nif [ -z \"${APOLLO_FRAMEWORK_PATH}\" ]; then\n echo \"error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project.\"\n exit 1\nfi\n\ncd ${SRCROOT}/Tests/GitHubAPI\nif [[ $SDK_NAME == *\"macos\"* ]]; then\n # Run the mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/Versions/Current/Resources/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nelse\n # Run the non-mac script\n\"${APOLLO_FRAMEWORK_PATH}\"/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --operationIdsPath=operationIdsPath.json --mergeInFieldsFromFragmentSpreads API.swift\nfi\n";
};
9FCE2D061E6C251100E34457 /* Generate Apollo Client API */ = {
isa = PBXShellScriptBuildPhase;
Expand All @@ -1052,7 +1076,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Do some magic so we can make sure `FRAMEWORK_SEARCH_PATHS` works correctly when there's a space in the scheme or the folder name.\nQUOTED_FRAMEWORK_SEARCH_PATHS=\\\"$(echo $FRAMEWORK_SEARCH_PATHS | tr -d '\"' | sed -e 's/ \\//\" \"\\//g')\\\"\n\n# Get the first result searching for the framework\nAPOLLO_FRAMEWORK_PATH=\"$(eval find ${QUOTED_FRAMEWORK_SEARCH_PATHS} -name \"Apollo.framework\" -maxdepth 1 -print | head -n 1)\"\n\nif [ -z \"${APOLLO_FRAMEWORK_PATH}\" ]; then\n echo \"error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project.\"\n exit 1\nfi\n\ncd ${SRCROOT}/Tests/StarWarsAPI\nif [[ $SDK_NAME == *\"macos\"* ]]; then\n # Run the mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/Versions/Current/Resources/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nelse\n # run the non-mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nfi\n";
shellScript = "# Do some magic so we can make sure `FRAMEWORK_SEARCH_PATHS` works correctly when there's a space in the scheme or the folder name.\nQUOTED_FRAMEWORK_SEARCH_PATHS=\\\"$(echo $FRAMEWORK_SEARCH_PATHS | tr -d '\"' | sed -e 's/ \\//\" \"\\//g')\\\"\n\n# Get the first result searching for the framework\nAPOLLO_FRAMEWORK_PATH=\"$(eval find ${QUOTED_FRAMEWORK_SEARCH_PATHS} -name \"Apollo.framework\" -maxdepth 1 -print | head -n 1)\"\n\nif [ -z \"${APOLLO_FRAMEWORK_PATH}\" ]; then\n echo \"error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project.\"\n exit 1\nfi\n\ncd ${SRCROOT}/Tests/StarWarsAPI\nif [[ $SDK_NAME == *\"macos\"* ]]; then\n # Run the mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/Versions/Current/Resources/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --mergeInFieldsFromFragmentSpreads API.swift\nelse\n # run the non-mac script\n \"${APOLLO_FRAMEWORK_PATH}\"/check-and-run-apollo-cli.sh codegen:generate --queries=\"$(find . -name '*.graphql')\" --schema=schema.json --operationIdsPath=operationIdsPath.json --mergeInFieldsFromFragmentSpreads API.swift\nfi\n";
};
/* End PBXShellScriptBuildPhase section */

Expand All @@ -1064,6 +1088,7 @@
9F8A95841EC0FD6100304A2D /* XCTestCase+Promise.swift in Sources */,
9F8A95821EC0FD3300304A2D /* XCTAssertHelpers.swift in Sources */,
9F10A51E1EC1BA0F0045E62B /* MockNetworkTransport.swift in Sources */,
F8AB781B22E1B4BB00A50B81 /* MockURLSession.swift in Sources */,
9F8A95861EC0FD9800304A2D /* TestCacheProvider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1151,6 +1176,7 @@
files = (
9FC9A9C81E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift in Sources */,
9F91CF8F1F6C0DB2008DD0BE /* MutatingResultsTests.swift in Sources */,
F82E62E122BCD223000C311B /* AutomaticPersistedQueriesTests.swift in Sources */,
9F19D8461EED8D3B00C57247 /* ResultOrPromiseTests.swift in Sources */,
9F533AB31E6C4A4200CBE097 /* BatchedLoadTests.swift in Sources */,
9B95EDC022CAA0B000702BB2 /* GETTransformerTests.swift in Sources */,
Expand Down
34 changes: 14 additions & 20 deletions Sources/Apollo/GraphQLGETTransformer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ struct GraphQLGETTransformer {
let body: GraphQLMap
let url: URL

private let variablesKey = "variables"
private let queryKey = "query"

/// A helper for transforming a GraphQLMap that can be sent with a `POST` request into a URL with query parameters for a `GET` request.
///
/// - Parameters:
Expand All @@ -35,26 +32,23 @@ struct GraphQLGETTransformer {
return nil
}

guard let query = self.body.jsonObject[self.queryKey] as? String else {
var queryItems: [URLQueryItem] = []

do {
_ = try body.sorted(by: {$0.key < $1.key}).compactMap({ arg in
if let value = arg.value as? GraphQLMap {
let data = try JSONSerialization.dataSortedIfPossible(withJSONObject: value.jsonValue)
if let string = String(data: data, encoding: .utf8) {
queryItems.append(URLQueryItem(name: arg.key, value: string))
}
} else if let string = arg.value as? String {
queryItems.append(URLQueryItem(name: arg.key, value: string))
}
})
designatednerd marked this conversation as resolved.
Show resolved Hide resolved
} catch {
return nil
}

var queryItems = components.queryItems ?? [URLQueryItem]()

queryItems.append(URLQueryItem(name: self.queryKey, value: query))
components.queryItems = queryItems

guard let variables = self.body.jsonObject[self.variablesKey] as? [String: Any] else {
return components.url
}

guard
let serializedData = try? JSONSerialization.dataSortedIfPossible(withJSONObject: variables),
let jsonString = String(bytes: serializedData, encoding: .utf8) else {
return components.url
}

queryItems.append(URLQueryItem(name: self.variablesKey, value: jsonString))
components.queryItems = queryItems

return components.url
Expand Down
6 changes: 6 additions & 0 deletions Sources/Apollo/GraphQLHTTPResponseError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ public struct GraphQLHTTPResponseError: Error, LocalizedError {
public enum ErrorKind {
case errorResponse
case invalidResponse
case persistedQueryNotFound
case persistedQueryNotSupported

var description: String {
switch self {
case .errorResponse:
return "Received error response"
case .invalidResponse:
return "Received invalid response"
case .persistedQueryNotFound:
return "Persisted query not found"
case .persistedQueryNotSupported:
return "Persisted query not supported"
}
}
}
Expand Down
Loading