← all adapters

photos-style

simulates Google Photos Library API v1

restadapter v0.1.012 routes

verification

VMVM tier — no SDK suite yet· surface 12 · not implemented 5 · differs 5

use it

# add to stunt.yaml
services:
  photos:
    adapter: embedded:photos-style

# then
$ stunt up

The embedded: source extracts this adapter from the binary — no git clone, fully offline.

how to mock the Google Photos Library API locally

Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Google Photos Library API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Google Photos Library API v1 surface — the data is fake, the behavior is real.

backing stores

tokensrefresh_tokenscodesupload_tokensmedia_itemsalbums

api surface (12)

generated from the adapter manifest — exactly what boots, nothing more

12 routes
GET/o/oauth2/auth
POST/o/oauth2/token
POST/v1/uploads
POST/v1/mediaItems:batchCreate
POST/v1/mediaItems:search
GET/v1/mediaItems
GET/v1/mediaItems/{id}
GET/v1/media-dl/{id}
GET/v1/albums
POST/v1/albums
GET/v1/albums/{id}
DELETE/v1/albums/{id}

VM-verified behaviors (50)

  • ✓authorize without redirect_uri, state or client_id is 400 invalid_request
  • ✓authorize redirects with a fresh code and echoes the state
  • ✓a redirect_uri that already carries a query joins with &
  • ✓exchanging an unknown code is 400 invalid_grant
  • ✓a client mismatch answers invalid_client but leaves the code usable
  • ✓the happy exchange mints the bearer pair
  • ✓the minted bearer reads the data plane
  • ✓authorization codes are single-use
  • ✓unknown grant types are unsupported_grant_type
  • ✓refresh without client credentials is 400 invalid_client
  • ✓refresh with an unknown refresh token is 400 invalid_grant
  • ✓refresh mints a new access token but keeps the refresh token
  • ✓the refreshed token serves the same user's library
  • ✓refresh-issued access tokens expire like any other
  • ✓every data surface answers 401 UNAUTHENTICATED without a bearer
  • ✓non-Bearer schemes and unknown or empty tokens are equally 401
  • ✓the minted bearer passes the gate on every surface
  • ✓the access token dies at its expiry on the virtual clock
  • ✓/v1/uploads answers a plain-text uploadToken
  • ✓batchCreate links the token to a media item
  • ✓mime types follow the file extension
  • ✓an unknown upload token answers the per-item status error
  • ✓mixed batches keep request order
  • ✓upload tokens are single-use
  • ✓an albumId is accepted without validation (as-is)
  • ✓an empty batch answers an empty result list
  • ✓=d serves the original bytes with the recorded content type
  • ✓=dv serves the same original bytes
  • ✓a bare baseUrl serves the derivative payload instead
  • ✓baseUrl is computed from the request host at read time
  • ✓unknown ids answer the 404 envelope
  • ✓pages walk by pageToken and the last partial page has no next
  • ✓the default page holds 25 items
  • ✓pageSize clamps at 100
  • ✓a single item fetch and the 404 envelope
  • ✓items are private to their user
  • ✓an unfiltered search returns everything in creation order
  • ✓mediaTypeFilter selects PHOTO or VIDEO by mime prefix
  • ✓dateFilter ranges and exact dates bound creationTime
  • ✓partial dates span their whole period
  • ✓multiple ranges are OR'd and keep upload order
  • ✓media type and date filters compose
  • ✓albumId scopes the search
  • ✓search paginates from the JSON body
  • ✓create returns the album shape
  • ✓a missing album title defaults to Untitled Album
  • ✓unknown albums answer the 404 envelope
  • ✓list walks pages with the 20 default and the 50 clamp
  • ✓albums are private to their user
  • ✓delete removes the album but leaves its media

Not implemented (5)

  • No album item management (addItems, removeItems, batchRemoveMediaItems)
  • No album title update (PATCH /v1/albums/{id})
  • No album enrichments (text, map) via addEnrichment
  • No shared albums (list, join, leave, unshare)
  • No favorites marking or favorite filtering in search

Differs from the real API (5)

  • Bare-id media download returns derivative bytes; =d/=dv return original upload
  • search honors mediaTypeFilter and dateFilter only (no contentFilter or album filters)
  • Naming both PHOTO and VIDEO in mediaTypeFilter silently keeps only the last; real API 400s
  • albumId in batchCreate is not validated; mediaItemsCount stays 0 and description is dropped
  • Deleting an album leaves its items findable via search {albumId}
want more of the Google Photos Library API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.