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