RestKit Cache Design ==================== This document outlines the design for a lightweight cache implementation for the RestKit framework. The goals of the cache are: * Provide support for offline access to data payloads * Provide storage of last modification times for etags * Provide cache policies at the client and request level * RKResponse should be able to answer - (BOOL)wasLoadedFromCache * Each RKClient has its own cache (path initialized by Base URL somehow?) * RKCache should have a storage policy. This should be settable to session (store for the run of the app) or permanently. Needs to store: * Key/values * Settable via NSURL (not resource path) Concerns: * Does this need to be harmonized with the managed object cache? Can it be? * Don't love how tightly coupled cacheing is in Three20. Want something more orthogonal. * How are we going to unit test this? Need to identify test cases... * Where does the cache loading logic go? Request queue? Client? Inside of RKRequest? New class? References: * TTURLCache * ASIDownloadCache ETags: * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html * Comes across as either "ETag" or "Etag" header * Should be contained to RKRequest / RKResponse (don't bleed through into the cache) * Needs to be added on load via If-None-Match Request cache policies: * RKClient should have a default cache policy that gets passed through to requests * RKRequest will have a cache policy property. This determines when and how to utilize the cache. * You should be able to bitwise | these together, i.e. RKRequestCachePolicyLoadIfOffline | RKRequestCachePolicyEtag typedef enum { RKRequestCachePolicyNone = 0, // Never use the cache RKRequestCachePolicyLoadIfOffline, // Load from the cache when we are offline RKRequestCachePolicyLoadOnError, // Load from the cache if we encounter an error RKRequestCachePolicyEtag, // Load from the cache if we have data stored and the server returns a 304 (not modified) response RKRequestCachePolicyDefault = RKRequestCachePolicyEtag; } RKRequestCachePolicy; ################################################################################### // Proposed Interface // Returns a cache key for a URL (md5 the full URL after coercing to a string) // This will let you work with the cache via URL's pretty easily - (NSString*)RKCacheKeyForURL:(NSURL*)URL; // Storage policy. Determines if we clear the cache out when the app is shut down. Cache // instance needs to register for typedef enum { RKCacheStoragePolicyDisabled, // The cache has been disabled. Attempts to store data will silently fail RKCacheStoragePolicyForDurationOfSession, // Cache data for the length of the session. Clear cache at app exit. RKCacheStoragePolicyPermanently // Cache data permanently, until explicitly expired or flushed } RKCacheStoragePolicy; @interface RKCache : NSObject { NSString* _cachePath; RKCacheStoragePolicy _storagePolicy; } @property (nonatomic, readonly) NSString* cachePath; // Full path to the cache @property (nonatomic, assign) RKCacheStoragePolicy storagePolicy; // User can change storage policy. // Should be initialized with the full path to store it. RKClient should // figure out the appropriate path when initializing. - (id)initWithCachePath:(NSString*)cachePath storagePolicy:(RKCacheStoragePolicy)storagePolicy; // Key/value storage - (NSString*)pathForKey:(NSString*)key; - (BOOL)hasDataForKey:(NSString*)key; - (void)storeData:(NSData*)data forKey:(NSString*)key; - (NSData*)dataForKey:(NSString*)key; - (NSData*)dataForKey:(NSString*)key expires:(NSTimeInterval)expirationAge timestamp:(NSDate**)timestamp; // Cache Invalidation - (void)invalidateKey:(NSString*)key; - (void)invalidateAll; @end // RKRequest Get new properties: NSString* cacheKey; // When GET, defaults to RKCacheKeyForURL. For POST/PUT, md5 of the serialization data. RKRequestCachePolicy cachePolicy; // Cache policy inherited from RKClient. // RKResponse BOOL wasLoadedFromCache; // YES when the response was built from cached data