How I replaced GTLR with a lean REST setup—token-based Google Drive integration using URLSession, safer secrets, and fewer moving parts.
GTLR is gone from my stack. I rebuilt file list, upload, and metadata calls with token-based Google Drive integration using pure REST and URLSession. The result: smaller binaries, clearer errors, and auth I actually understand. This post shows the moving pieces, pitfalls, and a copy-paste checklist you can apply today. For layout sanity while rebuilding screens, I leaned on Golden Scaling in Practice—pre-deciding anchors kept my UI and my head calm during refactors.
Why token-based Google Drive integration?
Libraries hide complexity—until they don’t. A direct REST approach gives you explicit control over scopes, refresh timing, and retries. With a short AuthService, I trade magical “it works” for transparent calls I can reason about. See my earlier context in LifeOS Dev Log: Drive Tokens & List/Grid Toggle for how this started.
Core flow for token-based Google Drive integration
- Sign in & get tokens. Use Google Sign-In to obtain an access token and refresh token (on first consent).
- Store securely. Keep tokens in Keychain; never in
UserDefaults or the document.
- Attach bearer. Each request sets
Authorization: Bearer <access_token>.
- Auto-refresh. On 401, refresh using the OAuth token endpoint and retry once.
- Call Drive v3. Hit
/drive/v3/files for list/search, /upload/drive/v3/files for media.
Minimal checklist for token-based Google Drive integration
- Scopes: request the smallest set that covers your features (
drive.file beats drive).
- Expiry: track
expires_in and refresh proactively at ~80% of lifetime.
- Retries: 1 refresh retry max; then sign-in flow.
- Logging: log request ids + status codes, redact tokens.
Endpoints you’ll call (REST)
- List files:
GET https://www.googleapis.com/drive/v3/files?q=name contains 'doc'&fields=files(id,name,mimeType,modifiedTime,size)
- Upload (simple):
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media
- Upload (multipart):
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart
- Refresh token:
POST https://oauth2.googleapis.com/token
The official references are clear and current: Drive API (REST) Overview and Google Identity: OAuth 2.0.
UI notes (because UX still matters)
Token work is plumbing; users feel rhythm. Anchor your headline on 3/5, your primary action (Upload / Connect) on 5/8, and stick to one gutter (8/13/21). These small rules keep “settings” screens from feeling like a spreadsheet.
Common mistakes (and quick fixes)
- Using broad scopes: start with
drive.file; escalate only if required.
- Storing tokens loosely: Keychain or secure enclave wrappers—always.
- No refresh guard: limit retries to prevent loops.
- JSON field bloat: set
fields= to exactly what you render; faster and cheaper.
- Blocking the UI: do I/O off the main actor; stream uploads when possible.
What I cut (and didn’t miss)
- Heavy client libs, auto-generated models, opaque errors.
- I kept: typed request builders, small decoders, and a single
HTTPClient with request/response logging (redacted).
Ship it
Start by swapping your file list screen to REST calls behind an AuthService. If it feels good, move uploads and metadata next. When you hit the first 401 in the wild, you’ll be glad you understand the flow. Download the starter snippet for URLSession + refresh and make your Drive calls boring—in the best way.
- randomblink
Drive Previews, Tag Chips, and Faster List↔Grid
Previews that land sooner, tags that filter smarter, and a list/grid toggle that stops jumping.
1) Drive previews: sooner, safer
- Parallel fetch with short deadline. We request preview URLs and content metadata in parallel; if a preview misses the deadline, a crisp type glyph renders instantly and the preview swaps in later.
- Cache keys that make sense.
fileId:modified:size prevents stale thumbs and avoids over-fetch.
- Fail gracefully. If a preview URL expires or fails, we retry once with backoff; otherwise we stay on the glyph—no flicker.
Tech: Google Drive v3 via REST + URLSession (no GTLR), tokens in Keychain, MIME + modified date for cache busting.
2) Tag chips: clearer states, fewer clicks
- Tap = add/remove, Option/Alt-tap (or long-press) = isolate.
- Three visual states (default / active ● / isolated ◎), not color-only—icons + contrast.
- Keyboard: press
t to focus chips; use arrow keys; Space toggles; Enter isolates.
Why it’s calmer: you see exactly what’s filtering, and you can isolate a single tag without hunting in a sidebar.
3) List ↔ Grid: faster and steady
- Per-section persistence. Projects can default to List; Resources can default to Grid; your picks stick via
UserDefaults.
- No layout jump. We normalize row heights and thumbnail placeholders so the header and chip row don’t jitter during toggles.
- Scroll position remembered across toggles within the same section.
Tiny wins that matter
- Progressive disclosure. Modified date and type inline; size/path appear on hover/focus.
- Focus rings you can see. Keyboard navigation is obvious and consistent.
- Touch targets. Chips and toggles are 44pt minimum.
Try it
- Toggle list↔grid in Resources; notice no header jump.
- Tap a couple of tags, then isolate one with Option/Alt.
- Open a large image folder—the first row should render fast with clean fallbacks.
What’s next
- Recents ranking v2 (boost multi-touch files over 48 hours).
- PDF inline preview (first page, cached).
- Session stacks (auto-bundle your last 60–90 minutes of files).
Internal & External Links
Update / Version Box
LifeOS — Dev Log #3
- Build:
0.1.0-dev (Swift 6, Xcode 16)
- Shipped: faster Drive previews, clearer tag chips, steadier list↔grid
- Known limits: giant PDFs still skip preview on slow networks
- Next: Recents ranking v2 + first-page PDF preview
Signature
— Rev. Brian Scott O’Keefe
“Less friction, more flow.”
Tokens, Sync, Clean Start
Current goals
- ✅ Go REST-only with tokens (ditch legacy SDK/gRPC/GTLR; rely on clean URLSession calls).
- ✅ Harden sign-in/out across macOS/iOS with a single source of truth for auth state.
- 🔄 Design a calmer file view that shows exactly what you need (and nothing you don’t).
- 📓 Make the logs the memory: short, truthful dev notes; tight screenshots; reproducible steps.
- 🧪 Stabilize sync for Drive/Calendar basics, then layer on previews and offline cache.
Auth & tokens (the new backbone)
The old way was tangled. The new way is simple:
- Token-based REST: standard OAuth2 flow → store access + refresh tokens in the Keychain; refresh automatically before expiry; never block the UI waiting on auth.
- Single Auth service: one AuthState drives UI. If isSignedIn == false, show a safe, minimal sign-in sheet; otherwise continue seamlessly.
- Sign-out that really signs out: clear tokens, reset caches, invalidate any background tasks, bounce the app to a clean state.
- Resilience first: every network call wraps:
- Retry on transient errors (exponential backoff).
- 401 → refresh token once → retry; if it fails, drop to signed-out.
- All errors surface as human-readable toasts and machine-readable logs.
What I broke today:
A silent refresh loop when the network dropped mid-refresh. Fixed by gating concurrent refresh calls and memoizing the in-flight promise so only one refresh can run at a time.
Privacy posture: tokens never leave the device; logs redact headers; no crash reports include PII.
File view ideas (don’t fight the brain)
I’m designing for calm and orientation:
- List ↔ Grid toggle with your last choice remembered.
- At-a-glance metadata: file type, size, modified date, and Drive ID (copy-on-click).
- Thumbnails/previews where useful; text-only for dense modes.
- Recents / Favorites tabs right on top.
- Inline filters (type, tag, owner) with a compact query pill you can edit.
- Breadcrumbs you can actually use (each crumb is clickable and copyable).
- One universal action key: ⏎ opens, ⌘C copies link/ID, Space previews.
- “What changed?” ghost highlights after a sync so your eyes find fresh stuff fast.
- Gentle empty states with a single next action (import, connect, or create).
Sketch note: the content column aligns to a golden-ratio container; actions hide until hover/focus to reduce visual noise.
Known bugs (current reality, not vibes)
- Folder lists sometimes load but aren’t clickable after a slow network wake. Likely a stale SwiftUI state binding—reloading the data source fixes it; investigating a proper identity key.
- Actor isolation warnings in Swift 6 where async services touch UI state (DrivePathResolver + cache).
- Occasional duplicate types after regenerating models (invalid redeclarations). Root cause: old files not removed during refactor; adding a “regenerate and prune” step.
- Ambiguous initializers in a mock service leading to “extra arguments” compile errors—cleaning up convenience inits and adopting builders for test data.
- Token refresh race (now fixed) caused a brief signed-out flicker on resume.
I’m keeping these here until each is closed and regression-tested.
Next sprint (tight, testable, shippable)
1) Auth polish
- Add a single-flight refresh guard (done), plus unit tests for: token expiry edge, network drop, revoked refresh token.
- Implement background refresh scheduling with OS hints to avoid wake storms.
2) File view MVP
- Ship List/Grid with: name, icon, size, modified, ID (copy-on-click).
- Add Recents/Favorites tabs and persist view mode in UserDefaults.
- Wire preview (Space) for images/PDF/text.
3) Sync + cache
- Local metadata cache keyed by Drive ID; optimistic UI for move/rename.
- Debounced search with cancellable tasks to keep typing smooth.
4) Quality gates
- “No new warnings” rule on main.
- Trace logs for every network call with request ID; redaction enforced in one place.
- Screenshot + short clip of each feature before merge (so this log has pictures).
CTA: Tell me your top pain in organizing files; I’ll test it in the next build.
Drop a comment or reply with a 1–2 sentence description (bonus: a quick phone snapshot of your folder chaos). Real pain > hypothetical features.
Changelog (human-sized)
- Refactor: Removed legacy SDK hooks; REST-only networking via URLSession.
- Auth: Centralized AuthState; fixed refresh loop; clearer error surfaces.
- Design: Spec’d calmer file view; golden-ratio container; copyable IDs.
- Tooling: Added request-ID tracing; started “screenshots or it didn’t happen” rule.
- randomblink