Skip to content

Instantly share code, notes, and snippets.

@andr3a88
Last active August 30, 2024 09:59
Show Gist options
  • Save andr3a88/2af66cd4c69448ec219cc7b20a93f4ed to your computer and use it in GitHub Desktop.
Save andr3a88/2af66cd4c69448ec219cc7b20a93f4ed to your computer and use it in GitHub Desktop.
Apollo iOS with AppSync custom body request: AppSyncRequestBodyCreator
/// Creates an AWS AppSync-compatible RequestBody `payload` for subscriptions.
/// This is necessary due to the different payload used by Apollo
/// Credit to:
/// - https://community.apollographql.com/t/using-apollo-with-appsync-directly-on-ios/324/4
/// - https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html#header-parameter-format-based-on-appsync-api-authorization-mode
/// - https://github.com/lingfengmarskey/NetworkSample
///
/// AppSync payload:
/// {
/// "id": "subscriptionId",
/// "type": "start",
/// "payload": {
/// "data": { // Data object as a string value
/// "query": "query string",
/// "variables": "variables"
/// },
/// "extensions": {
/// "authorization": {
/// "host": "host",
/// "Authorization": "AccessToken"
/// }
/// }
/// }
/// }
public class AppSyncRequestBodyCreator: RequestBodyCreator {
private var accessToken: String
init(accessToken: String) {
self.accessToken = accessToken
}
public func requestBody<Operation: GraphQLOperation>(for operation: Operation,
sendQueryDocument: Bool,
autoPersistQuery: Bool ) -> JSONEncodableDictionary {
let authorization = buildAuthenticationPayload(accessToken: accessToken)
var body: JSONEncodableDictionary = [ "operationName": Operation.operationName ]
var dataDictionary = JSONEncodableDictionary()
if let variables = operation.__variables {
dataDictionary["variables"] = variables._jsonEncodableObject
}
if sendQueryDocument {
guard let document = Operation.definition?.queryDocument else {
preconditionFailure("To send query documents, Apollo types must be generated with `OperationDefinition`s.")
}
dataDictionary["query"] = document
}
guard let dataJson = dataDictionary.toData() else {
preconditionFailure("query and variables are not a valid JSON")
}
body["data"] = String(decoding: dataJson, as: UTF8.self)
if autoPersistQuery {
guard let operationIdentifier = Operation.operationIdentifier else {
preconditionFailure("To enable `autoPersistQueries`, Apollo types must be generated with operationIdentifiers")
}
body["extensions"] = [
"persistedQuery": ["sha256Hash": operationIdentifier, "version": 1],
"authorization": authorization ]
} else {
body["extensions"] = ["authorization": authorization]
}
return body
}
/// Build the authentication payload for the WebSocket connection
/// {
/// "host": "<host>",
/// "Authorization": "Authorization"
/// }
private func buildAuthenticationPayload(accessToken: String) -> JSONEncodableDictionary {
let host = graphQlUrl
.replacingOccurrences(of: "https://", with: "")
.replacingOccurrences(of: "/graphql", with: "")
let authPayload: JSONEncodableDictionary = ["host": host,
"Authorization": "\(accessToken)"]
return authPayload
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment