- name
- http-cache
- description
- Generates an HTTP caching layer with Cache-Control parsing, ETag/conditional requests, and offline fallback. Use when user wants to add response caching, offline support, or reduce API calls.
- allowed-tools
- ["Read","Write","Edit","Glob","Grep","Bash","AskUserQuestion"]
- last_verified
- 2026-07-16T00:00:00.000Z
- review_by
- 2027-06-22T00:00:00.000Z
- os_version
- iOS 27 / macOS 27
# HTTP Cache Generator
Generate a production HTTP caching layer that integrates with your existing networking code. Supports Cache-Control directives, ETag/Last-Modified conditional requests, stale-while-revalidate, and offline fallback.
## When This Skill Activates
Use this skill when the user:
- Asks to "add HTTP caching" or "cache API responses"
- Wants "offline support" or "offline fallback"
- Mentions "reduce API calls" or "cache network responses"
- Asks about "ETag" or "conditional requests" or "304 Not Modified"
- Wants "stale-while-revalidate" behavior
## Pre-Generation Checks
### 1. Project Context Detection
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Check deployment target (iOS 16+ / macOS 13+)
- [ ] Search for existing caching implementations
- [ ] Identify source file locations
### 2. Networking Layer Detection
Search for existing networking code:
```
Glob: **/*API*.swift, **/*Client*.swift, **/*Network*.swift
Grep: "APIClient" or "URLSession" or "HTTPURLResponse"
```
If `networking-layer` generator was used, detect the `APIClient` protocol and generate a decorator that wraps it.
### 3. Conflict Detection
Search for existing caching:
```
Glob: **/*Cache*.swift
Grep: "URLCache" or "ResponseCache" or "CachePolicy"
```
If found, ask user whether to replace or extend.
## Configuration Questions
Ask user via AskUserQuestion:
1. **Cache storage sizes?**
- Small (10 MB memory / 50 MB disk)
- Medium (25 MB memory / 100 MB disk) — recommended
- Large (50 MB memory / 250 MB disk)
2. **Caching strategy?**
- Respect server Cache-Control headers (standard)
- Cache-first with background revalidation (stale-while-revalidate)
- Manual per-endpoint policies
3. **Offline support?**
- Yes — serve stale cache when network unavailable
- No — only cache while online
4. **Integration style?**
- Decorator wrapping existing APIClient (recommended if networking-layer exists)
- Standalone cache you call directly
## Generation Process
### Step 1: Read Templates
Read `http-cache-patterns.md` for architecture guidance.
Read `templates.md` for production Swift code.
### Step 2: Create Core Files
Generate these files:
1. `HTTPCacheConfiguration.swift` — Memory/disk sizes, default policy
2. `CachePolicy.swift` — Per-endpoint enum (default, noCache, forceCache, cacheFirst)
3. `CacheControlHeader.swift` — Cache-Control header parser
4. `ConditionalRequestHandler.swift` — ETag/Last-Modified/304 handling
5. `HTTPResponseCache.swift` — Protocol + disk-backed response store
### Step 3: Create Integration Files
Based on configuration:
- `CachingAPIClient.swift` — Decorator wrapping existing APIClient (if decorator style)
- `NetworkReachability.swift` — NWPathMonitor wrapper (if offline support selected)
### Step 4: Determine File Location
Check project structure:
- If `Sources/Networking/` exists → `Sources/Networking/Cache/`
- If `App/Networking/` exists → `App/Networking/Cache/`
- If `Networking/` exists → `Networking/Cache/`
- Otherwise → `Cache/`
## Output Format
After generation, provide:
### Files Created
```
Networking/Cache/
├── HTTPCacheConfiguration.swift # Memory/disk sizes, default policy
├── CachePolicy.swift # Per-endpoint caching enum
├── CacheControlHeader.swift # Cache-Control header parser
├── ConditionalRequestHandler.swift # ETag/Last-Modified/304
├── HTTPResponseCache.swift # Protocol + disk implementation
├── CachingAPIClient.swift # Decorator for existing APIClient
└── NetworkReachability.swift # NWPathMonitor (optional)
```
### Integration Steps
**Wrap your existing client:**
```swift
let baseClient = URLSessionAPIClient(configuration: .production)
let cachingClient = CachingAPIClient(
wrapping: baseClient,
cache: DiskHTTPResponseCache(),
configuration: .default
)
// Use cachingClient everywhere you used baseClient
let users = try await cachingClient.request(UsersEndpoint())
```
**Per-endpoint cache policy:**
```swift
struct UsersEndpoint: APIEndpoint, CacheConfigurable {
var cachePolicy: CachePolicy { .cacheFirst(maxAge: 300) }
}
struct OrdersEndpoint: APIEndpoint, CacheConfigurable {
var cachePolicy: CachePolicy { .noCache }
}
```
**With SwiftUI:**
```swift
struct UsersView: View {
@Environment(\.apiClient) private var apiClient
var body: some View {
List(users) { user in
Text(user.name)
}
.task {
// Automatically uses cache if available
users = try await apiClient.request(UsersEndpoint())
}
}
}
```
### Testing
```swift
@Test
func cachedResponseReturnedOnSecondRequest() async throws {
let mockClient = MockAPIClient()
let cache = InMemoryHTTPResponseCache()
let cachingClient = CachingAPIClient(wrapping: mockClient, cache: cache)
mockClient.mockResponse(for: UsersEndpoint.self, response: [.mock])
// First request hits network
let first = try await cachingClient.request(UsersEndpoint())
#expect(mockClient.requestCount == 1)
// Second request comes from cache
let second = try await cachingClient.request(UsersEndpoint())
#expect(mockClient.requestCount == 1) // No additional network call
#expect(first == second)
}
```
## References
- **http-cache-patterns.md** — Cache-Control directives, ETag flow, stale-while-revalidate
- **templates.md** — All production Swift templates
- Related: `generators/networking-layer` — Base networking layer this decorates
View on GitHub