[BREAKGLASS] Modern Google Places CLI in Go https://goplaces.sh/
Go to file
aligurelli 17728bacc8
Add userRatingCount support (#3)
* feat: add userRatingCount to search, nearby, and details

Add the userRatingCount field from the Google Places API (New) to
PlaceSummary and PlaceDetails types. This allows consumers to see
the total number of user ratings for each place.

Changes:
- Add userRatingCount to search, nearby, and details field masks
- Add UserRatingCount field to placeItem payload struct
- Add UserRatingCount to PlaceSummary and PlaceDetails types
- Map the field in mapPlaceSummary and mapPlaceDetails
- Display rating count in CLI output as 'Rating: 4.5 (532)'
- Include as 'user_rating_count' in JSON output

* fix: handle rating-count rendering fallback and add regressions

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 05:12:24 +01:00
.github/workflows ci: install golangci-lint v2 2026-01-02 20:42:10 +01:00
cmd/goplaces fix: add cli package comment 2026-01-02 20:48:27 +01:00
docs fix: harden route command 2026-01-02 22:38:59 +01:00
internal/cli Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
scripts feat: bootstrap goplaces 2026-01-02 17:21:02 +01:00
.gitignore fix: add cli package comment 2026-01-02 20:48:27 +01:00
.golangci.yml chore: fix lint config and docs 2026-01-02 17:35:00 +01:00
.goreleaser.yml chore(release): add windows arm64 target 2026-01-09 23:36:56 +01:00
autocomplete.go feat: add autocomplete support 2026-01-02 21:24:55 +01:00
CHANGELOG.md chore: start 0.2.2 changelog 2026-01-24 00:08:29 +00:00
client_test.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
client.go fix: harden route command 2026-01-02 22:38:59 +01:00
details.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
e2e_test.go feat: add photo support 2026-01-02 21:37:23 +01:00
errors_test.go feat: bootstrap goplaces 2026-01-02 17:21:02 +01:00
errors.go feat: bootstrap goplaces 2026-01-02 17:21:02 +01:00
go.mod feat: bootstrap goplaces 2026-01-02 17:21:02 +01:00
go.sum feat: bootstrap goplaces 2026-01-02 17:21:02 +01:00
LICENSE Initial commit 2026-01-02 16:49:23 +01:00
limits.go feat: add nearby search 2026-01-02 21:30:33 +01:00
Makefile build: always rebuild goplaces target 2026-01-10 18:56:12 +01:00
mapping.go feat: add photo support 2026-01-02 21:37:23 +01:00
nearby.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
payloads.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
photo.go feat: add photo support 2026-01-02 21:37:23 +01:00
price_levels.go feat: add autocomplete support 2026-01-02 21:24:55 +01:00
README.md chore: update 0.2.1 docs and equals-flag tests 2026-01-23 11:59:45 +00:00
request_helpers.go feat: add autocomplete support 2026-01-02 21:24:55 +01:00
resolve.go feat: add autocomplete support 2026-01-02 21:24:55 +01:00
route_test.go test: expand route coverage 2026-01-02 23:01:29 +01:00
route.go fix: harden route command 2026-01-02 22:38:59 +01:00
search.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
types.go Add userRatingCount support (#3) 2026-02-14 05:12:24 +01:00
validation.go feat: add autocomplete support 2026-01-02 21:24:55 +01:00

📍 goplaces — Modern Places for Go

Modern Go client + CLI for the Google Places API (New). Fast for humans, tidy for scripts.

Highlights

  • Text search with filters: keyword, type, open now, min rating, price levels.
  • Autocomplete suggestions for places + queries (session tokens supported).
  • Nearby search around a location restriction.
  • Place photos in details + photo media URLs.
  • Route search along a driving path (Routes API).
  • Location bias (lat/lng/radius) and pagination tokens.
  • Place details: hours, phone, website, rating, price, types.
  • Optional reviews in details (--reviews / IncludeReviews).
  • Resolve free-form location strings to candidate places.
  • Locale hints (language + region) across search/resolve/details.
  • Typed models, validation errors, and API error surfacing.
  • CLI with color human output + --json (respects NO_COLOR).

Install / Run

Latest release: v0.2.1 (2026-01-23).

  • Homebrew: brew install steipete/tap/goplaces
  • Go: go install github.com/steipete/goplaces/cmd/goplaces@latest
  • Source: make goplaces

Config

export GOOGLE_PLACES_API_KEY="..."

Optional overrides:

  • GOOGLE_PLACES_BASE_URL (testing, proxying, or mock servers)
  • GOOGLE_ROUTES_BASE_URL (testing Routes API or proxying)

Getting a Google Places API Key

  1. Create a Google Cloud Project

    • Go to Google Cloud Console
    • Click "Select a project" → "New Project"
    • Name it (e.g., "goplaces") and click "Create"
  2. Enable the Places API (New)

  3. Enable the Routes API (for route)

    • Search for "Routes API"
    • Click "Enable"
  4. Create an API Key

  5. Set the Environment Variable

    export GOOGLE_PLACES_API_KEY="your-api-key-here"
    

    Add to your ~/.zshrc or ~/.bashrc to persist.

  6. (Recommended) Restrict the Key

    • Click on the key in Credentials
    • Under "API restrictions", select "Restrict key" → "Places API (New)"
    • Set quota limits in Quotas

Note

: The Places API has usage costs. Check pricing and set budget alerts!

CLI

Long flags accept --flag value or --flag=value (examples use space).

goplaces [--api-key=KEY] [--base-url=URL] [--routes-base-url=URL] [--timeout=10s] [--json] [--no-color] [--verbose]
         <command>

Commands:
  autocomplete  Autocomplete places and queries.
  nearby        Search nearby places by location.
  search   Search places by text query.
  route    Search places along a route.
  details  Fetch place details by place ID.
  photo    Fetch a photo URL by photo name.
  resolve  Resolve a location string to candidate places.

Search with filters + location bias:

goplaces search "coffee" --min-rating 4 --open-now --limit 5 \
  --lat 40.8065 --lng -73.9719 --radius-m 3000 --language en --region US

Pagination:

goplaces search "pizza" --page-token "NEXT_PAGE_TOKEN"

Autocomplete:

goplaces autocomplete "cof" --session-token "goplaces-demo" --limit 5 --language en --region US

Nearby search:

goplaces nearby --lat 47.6062 --lng -122.3321 --radius-m 1500 --type cafe --limit 5

Route search:

goplaces route "coffee" --from "Seattle, WA" --to "Portland, OR" --max-waypoints 5

Details (with reviews):

goplaces details ChIJN1t_tDeuEmsRUsoyG83frY4 --reviews

Details (with photos):

goplaces details ChIJN1t_tDeuEmsRUsoyG83frY4 --photos

Photo URL:

goplaces photo "places/PLACE_ID/photos/PHOTO_ID" --max-width 1200

Resolve:

goplaces resolve "Riverside Park, New York" --limit 5

JSON output:

goplaces search "sushi" --json

Library

boolPtr := func(v bool) *bool { return &v }
floatPtr := func(v float64) *float64 { return &v }

client := goplaces.NewClient(goplaces.Options{
    APIKey:  os.Getenv("GOOGLE_PLACES_API_KEY"),
    Timeout: 8 * time.Second,
})

search, err := client.Search(ctx, goplaces.SearchRequest{
    Query: "italian restaurant",
    Filters: &goplaces.Filters{
        OpenNow:   boolPtr(true),
        MinRating: floatPtr(4.0),
        Types:     []string{"restaurant"},
    },
    LocationBias: &goplaces.LocationBias{Lat: 40.8065, Lng: -73.9719, RadiusM: 3000},
    Language:     "en",
    Region:       "US",
    Limit:        10,
})

details, err := client.DetailsWithOptions(ctx, goplaces.DetailsRequest{
    PlaceID:        "ChIJN1t_tDeuEmsRUsoyG83frY4",
    Language:       "en",
    Region:         "US",
    IncludeReviews: true,
})

autocomplete, err := client.Autocomplete(ctx, goplaces.AutocompleteRequest{
    Input:        "cof",
    SessionToken: "goplaces-demo",
    Limit:        5,
    Language:     "en",
    Region:       "US",
})

nearby, err := client.NearbySearch(ctx, goplaces.NearbySearchRequest{
    LocationRestriction: &goplaces.LocationBias{Lat: 47.6062, Lng: -122.3321, RadiusM: 1500},
    IncludedTypes:       []string{"cafe"},
    Limit:               5,
})

photo, err := client.PhotoMedia(ctx, goplaces.PhotoMediaRequest{
    Name:       "places/PLACE_ID/photos/PHOTO_ID",
    MaxWidthPx: 1200,
})

route, err := client.Route(ctx, goplaces.RouteRequest{
    Query:        "coffee",
    From:         "Seattle, WA",
    To:           "Portland, OR",
    MaxWaypoints: 5,
})

Notes

  • Filters.Types maps to includedType (Google accepts a single value). Only the first type is sent.
  • Price levels map to Google enums: 0 (free) → 4 (very expensive).
  • Reviews are returned only when IncludeReviews/--reviews is set.
  • Photos are returned only when IncludePhotos/--photos is set.
  • Route search requires the Google Routes API to be enabled.
  • Field masks are defined alongside each request (e.g. search.go, details.go, autocomplete.go).
  • The Places API is billed and quota-limited; keep an eye on your Cloud Console quotas.

Testing

make lint test coverage

E2E tests (optional)

export GOOGLE_PLACES_API_KEY="..."
make e2e

Optional env overrides:

  • Use a custom endpoint (proxy/mock): GOOGLE_PLACES_E2E_BASE_URL
  • Override the search text used in E2E: GOOGLE_PLACES_E2E_QUERY
  • Override language code for E2E: GOOGLE_PLACES_E2E_LANGUAGE
  • Override region code for E2E: GOOGLE_PLACES_E2E_REGION