← 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.