Enabling cache for AWS AppSync Client iOS Swift

1.4k views Asked by At

I am using AWS AppSync for creating my iOS application. I want to leverage the offline mutation as well as query caching provided by AppSync. But when I am turning my internet off, I am not getting any response. Rather its showing an error as "The Internet connection appears to be offline.". This seems to be rather an Alamofire exception than an AppSync exception. This is because the query is not getting cached inside my device. Following is my code snippet to initialize the client.

do {
    let appSyncClientConfig = try AWSAppSyncClientConfiguration.init(url: AWSConstants.APP_SYNC_ENDPOINT, serviceRegion: AWSConstants.AWS_REGION, userPoolsAuthProvider: MyCognitoUserPoolsAuthProvider())
    AppSyncHelper.shared.appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncClientConfig)
    AppSyncHelper.shared.appSyncClient?.apolloClient?.cacheKeyForObject = { $0["id"] }
} catch {
    print("Error in initializing the AppSync Client")
    print("Error: \(error)")
    UserDefaults.standard.set(nil, forKey: DeviceConstants.ID_TOKEN)
}

I am caching the token in the UserDefaults at the time of fetching the session, and then whenever the AppSyncClient is called, it fetches the latest token by calling the getLatestAuthToken() method of my MyCognitoUserPoolsAuthProvider: AWSCognitoUserPoolsAuthProvider. This is returning the token stored in the UserDefaults -

// background thread - asynchronous
func getLatestAuthToken() -> String {
    print("Inside getLatestAuthToken")
    var token: String? = nil
    if let tokenString = UserDefaults.standard.string(forKey: DeviceConstants.ID_TOKEN) {
        token = tokenString
        return token!
    }
    return token!
}

My query pattern is the following

public func getUserProfile(userId: String, success: @escaping (ProfileModel) -> Void, failure: @escaping (NSError) -> Void) {
    let getQuery = GetUserProfileQuery(id: userId)
    print("getQuery.id: \(getQuery.id)")
    if appSyncClient != nil {
        print("AppSyncClient is not nil")
        appSyncClient?.fetch(query: getQuery, cachePolicy: CachePolicy.returnCacheDataElseFetch, queue: DispatchQueue.global(qos: .background), resultHandler: { (result, error) in
            if error != nil {
                failure(error! as NSError)
            } else {
                var profileModel = ProfileModel()
                print("result: \(result)")
                if let data = result?.data {
                    print("data: \(data)")
                    if let userProfile = data.snapshot["getUserProfile"] as? [String: Any?] {
                        profileModel = ProfileModel(id: UserDefaults.standard.string(forKey: DeviceConstants.USER_ID), username: userProfile["username"] as? String, mobileNumber: userProfile["mobileNumber"] as? String, name: userProfile["name"] as? String, gender: (userProfile["gender"] as? Gender).map { $0.rawValue }, dob: userProfile["dob"] as? String, profilePicUrl: userProfile["profilePicUrl"] as? String)
                    } else {
                        print("data snapshot is nil")
                    }
                }
                success(profileModel)
            }
        })
    } else {
        APPUtilites.displayErrorSnackbar(message: "Error in the user session. Please login again")
    }
}

I have used all the 4 CachePolicy objects provided by AppSync, i.e,

CachePolicy.returnCacheDataElseFetch
CachePolicy.fetchIgnoringCacheData
CachePolicy.returnCacheDataDontFetch
CachePolicy.returnCacheDataAndFetch.

Can someone help me in implementing the cache properly for my iOS app so that I can do queries without the internet also?

1

There are 1 answers

1
Kanhai Agarwal On

Okay so I found the answer myself. The databaseUrl is an optional argument. It does not come in the suggestions when we are initializing the AWSAppSyncClientConfiguration object.

So the new way in which I initialized the client is the following

let databaseURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(AWSConstants.DATABASE_NAME, isDirectory: false)
    do {
        let appSyncClientConfig = try AWSAppSyncClientConfiguration.init(url: AWSConstants.APP_SYNC_ENDPOINT,
                           serviceRegion: AWSConstants.AWS_REGION,
                           userPoolsAuthProvider: MyCognitoUserPoolsAuthProvider(),
                           urlSessionConfiguration: URLSessionConfiguration.default,
                           databaseURL: databaseURL)
        AppSyncHelper.shared.appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncClientConfig)

        AppSyncHelper.shared.appSyncClient?.apolloClient?.cacheKeyForObject = { $0["id"] }
    } catch {
        print("Error in initializing the AppSync Client")
        print("Error: \(error)")
    }

Hope it helps.