goplaces

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 13 Imported by: 0

README

📍 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).
  • Directions between two points with distance, duration, and steps (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)
  • GOOGLE_DIRECTIONS_BASE_URL (testing Routes API directions calls 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 and directions)

    • 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" → add "Places API (New)" and "Routes API"
    • 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] [--directions-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.
  directions  Get directions between two points.
  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

Directions (walking with optional driving comparison):

goplaces directions --from "Pike Place Market" --to "Space Needle"
goplaces directions --from-place-id <fromId> --to-place-id <toId> --compare drive --steps

Units (default metric):

goplaces directions --from "Pike Place Market" --to "Space Needle" --units imperial

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

Documentation

Overview

Package goplaces provides a Go client for the Google Places API (New).

Index

Constants

View Source
const DefaultBaseURL = "https://places.googleapis.com/v1"

DefaultBaseURL is the default endpoint for the Places API (New).

Variables

View Source
var ErrMissingAPIKey = fmt.Errorf("goplaces: missing api key")

ErrMissingAPIKey indicates a missing API key.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	StatusCode int
	Body       string
}

APIError represents an HTTP error from the Places API.

func (*APIError) Error

func (e *APIError) Error() string

type AuthorAttribution

type AuthorAttribution struct {
	DisplayName string `json:"display_name,omitempty"`
	URI         string `json:"uri,omitempty"`
	PhotoURI    string `json:"photo_uri,omitempty"`
}

AuthorAttribution describes a review author.

type AutocompleteRequest added in v0.2.0

type AutocompleteRequest struct {
	Input        string        `json:"input"`
	SessionToken string        `json:"session_token,omitempty"`
	Limit        int           `json:"limit,omitempty"`
	Language     string        `json:"language,omitempty"`
	Region       string        `json:"region,omitempty"`
	LocationBias *LocationBias `json:"location_bias,omitempty"`
}

AutocompleteRequest defines input for autocomplete suggestions.

type AutocompleteResponse added in v0.2.0

type AutocompleteResponse struct {
	Suggestions []AutocompleteSuggestion `json:"suggestions"`
}

AutocompleteResponse contains suggestions from autocomplete.

type AutocompleteSuggestion added in v0.2.0

type AutocompleteSuggestion struct {
	Kind           string   `json:"kind"`
	PlaceID        string   `json:"place_id,omitempty"`
	Place          string   `json:"place,omitempty"`
	Text           string   `json:"text,omitempty"`
	MainText       string   `json:"main_text,omitempty"`
	SecondaryText  string   `json:"secondary_text,omitempty"`
	Types          []string `json:"types,omitempty"`
	DistanceMeters *int     `json:"distance_meters,omitempty"`
}

AutocompleteSuggestion is a place or query prediction.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client wraps access to the Google Places API.

func NewClient

func NewClient(opts Options) *Client

NewClient builds a client with sane defaults.

func (*Client) Autocomplete added in v0.2.0

func (c *Client) Autocomplete(ctx context.Context, req AutocompleteRequest) (AutocompleteResponse, error)

Autocomplete returns place and query suggestions for an input string.

func (*Client) Details

func (c *Client) Details(ctx context.Context, placeID string) (PlaceDetails, error)

Details fetches details for a specific place ID.

func (*Client) DetailsWithOptions

func (c *Client) DetailsWithOptions(ctx context.Context, req DetailsRequest) (PlaceDetails, error)

DetailsWithOptions fetches place details with locale hints.

func (*Client) Directions added in v0.3.0

func (c *Client) Directions(ctx context.Context, req DirectionsRequest) (DirectionsResponse, error)

Directions fetches directions between two locations using the Routes API.

func (*Client) NearbySearch added in v0.2.0

func (c *Client) NearbySearch(ctx context.Context, req NearbySearchRequest) (NearbySearchResponse, error)

NearbySearch performs a nearby search around a location restriction.

func (*Client) PhotoMedia added in v0.2.0

func (c *Client) PhotoMedia(ctx context.Context, req PhotoMediaRequest) (PhotoMediaResponse, error)

PhotoMedia fetches a photo URL for a photo resource name.

func (*Client) Resolve

Resolve converts a free-form location string into candidate places.

func (*Client) Route added in v0.2.0

func (c *Client) Route(ctx context.Context, req RouteRequest) (RouteResponse, error)

Route searches for places along a route between two locations.

func (*Client) Search

func (c *Client) Search(ctx context.Context, req SearchRequest) (SearchResponse, error)

Search performs a text search with optional filters.

type DetailsRequest

type DetailsRequest struct {
	PlaceID  string `json:"place_id"`
	Language string `json:"language,omitempty"`
	Region   string `json:"region,omitempty"`
	// IncludeReviews requests the reviews field in Place Details.
	IncludeReviews bool `json:"include_reviews,omitempty"`
	// IncludePhotos requests the photos field in Place Details.
	IncludePhotos bool `json:"include_photos,omitempty"`
}

DetailsRequest fetches place details with optional locale hints.

type DirectionsRequest added in v0.3.0

type DirectionsRequest struct {
	From         string  `json:"from,omitempty"`
	To           string  `json:"to,omitempty"`
	FromPlaceID  string  `json:"from_place_id,omitempty"`
	ToPlaceID    string  `json:"to_place_id,omitempty"`
	FromLocation *LatLng `json:"from_location,omitempty"`
	ToLocation   *LatLng `json:"to_location,omitempty"`
	Mode         string  `json:"mode,omitempty"`
	Language     string  `json:"language,omitempty"`
	Region       string  `json:"region,omitempty"`
	Units        string  `json:"units,omitempty"`
}

DirectionsRequest describes a directions query between two locations.

type DirectionsResponse added in v0.3.0

type DirectionsResponse struct {
	Mode            string           `json:"mode"`
	Summary         string           `json:"summary,omitempty"`
	StartAddress    string           `json:"start_address,omitempty"`
	EndAddress      string           `json:"end_address,omitempty"`
	DistanceText    string           `json:"distance_text,omitempty"`
	DistanceMeters  int              `json:"distance_meters,omitempty"`
	DurationText    string           `json:"duration_text,omitempty"`
	DurationSeconds int              `json:"duration_seconds,omitempty"`
	Warnings        []string         `json:"warnings,omitempty"`
	Steps           []DirectionsStep `json:"steps,omitempty"`
}

DirectionsResponse contains a single route summary and steps.

type DirectionsStep added in v0.3.0

type DirectionsStep struct {
	Instruction     string `json:"instruction,omitempty"`
	DistanceText    string `json:"distance_text,omitempty"`
	DistanceMeters  int    `json:"distance_meters,omitempty"`
	DurationText    string `json:"duration_text,omitempty"`
	DurationSeconds int    `json:"duration_seconds,omitempty"`
	TravelMode      string `json:"travel_mode,omitempty"`
	Maneuver        string `json:"maneuver,omitempty"`
}

DirectionsStep is a single navigation step.

type Filters

type Filters struct {
	Keyword     string   `json:"keyword,omitempty"`
	Types       []string `json:"types,omitempty"`
	OpenNow     *bool    `json:"open_now,omitempty"`
	MinRating   *float64 `json:"min_rating,omitempty"`
	PriceLevels []int    `json:"price_levels,omitempty"`
}

Filters are optional search refinements.

type LatLng

type LatLng struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

LatLng holds geographic coordinates.

type LocalizedText

type LocalizedText struct {
	Text         string `json:"text,omitempty"`
	LanguageCode string `json:"language_code,omitempty"`
}

LocalizedText is a text value with an optional language code.

type LocationBias

type LocationBias struct {
	Lat     float64 `json:"lat"`
	Lng     float64 `json:"lng"`
	RadiusM float64 `json:"radius_m"`
}

LocationBias limits search results to a circular area.

type LocationResolveRequest

type LocationResolveRequest struct {
	LocationText string `json:"location_text"`
	Limit        int    `json:"limit,omitempty"`
	Language     string `json:"language,omitempty"`
	Region       string `json:"region,omitempty"`
}

LocationResolveRequest resolves a text location into place candidates.

type LocationResolveResponse

type LocationResolveResponse struct {
	Results []ResolvedLocation `json:"results"`
}

LocationResolveResponse contains resolved locations.

type NearbySearchRequest added in v0.2.0

type NearbySearchRequest struct {
	LocationRestriction *LocationBias `json:"location_restriction,omitempty"`
	Limit               int           `json:"limit,omitempty"`
	IncludedTypes       []string      `json:"included_types,omitempty"`
	ExcludedTypes       []string      `json:"excluded_types,omitempty"`
	Language            string        `json:"language,omitempty"`
	Region              string        `json:"region,omitempty"`
}

NearbySearchRequest defines a nearby search query.

type NearbySearchResponse added in v0.2.0

type NearbySearchResponse struct {
	Results       []PlaceSummary `json:"results"`
	NextPageToken string         `json:"next_page_token,omitempty"`
}

NearbySearchResponse contains nearby search results.

type Options

type Options struct {
	APIKey            string
	BaseURL           string
	RoutesBaseURL     string
	DirectionsBaseURL string
	HTTPClient        *http.Client
	Timeout           time.Duration
}

Options configures the Places client.

type Photo added in v0.2.0

type Photo struct {
	Name               string              `json:"name,omitempty"`
	WidthPx            int                 `json:"width_px,omitempty"`
	HeightPx           int                 `json:"height_px,omitempty"`
	AuthorAttributions []AuthorAttribution `json:"author_attributions,omitempty"`
}

Photo describes photo metadata for a place.

type PhotoMediaRequest added in v0.2.0

type PhotoMediaRequest struct {
	Name        string `json:"name"`
	MaxWidthPx  int    `json:"max_width_px,omitempty"`
	MaxHeightPx int    `json:"max_height_px,omitempty"`
}

PhotoMediaRequest fetches a photo URL from a photo resource name.

type PhotoMediaResponse added in v0.2.0

type PhotoMediaResponse struct {
	Name     string `json:"name,omitempty"`
	PhotoURI string `json:"photo_uri,omitempty"`
}

PhotoMediaResponse contains the photo URL for a photo name.

type PlaceDetails

type PlaceDetails struct {
	PlaceID         string   `json:"place_id"`
	Name            string   `json:"name,omitempty"`
	Address         string   `json:"address,omitempty"`
	Location        *LatLng  `json:"location,omitempty"`
	Rating          *float64 `json:"rating,omitempty"`
	UserRatingCount *int     `json:"user_rating_count,omitempty"`
	PriceLevel      *int     `json:"price_level,omitempty"`
	Types           []string `json:"types,omitempty"`
	Phone           string   `json:"phone,omitempty"`
	Website         string   `json:"website,omitempty"`
	Hours           []string `json:"hours,omitempty"`
	OpenNow         *bool    `json:"open_now,omitempty"`
	Reviews         []Review `json:"reviews,omitempty"`
	Photos          []Photo  `json:"photos,omitempty"`
}

PlaceDetails is a detailed view of a place.

type PlaceSummary

type PlaceSummary struct {
	PlaceID         string   `json:"place_id"`
	Name            string   `json:"name,omitempty"`
	Address         string   `json:"address,omitempty"`
	Location        *LatLng  `json:"location,omitempty"`
	Rating          *float64 `json:"rating,omitempty"`
	UserRatingCount *int     `json:"user_rating_count,omitempty"`
	PriceLevel      *int     `json:"price_level,omitempty"`
	Types           []string `json:"types,omitempty"`
	OpenNow         *bool    `json:"open_now,omitempty"`
}

PlaceSummary is a compact view of a place.

type ResolvedLocation

type ResolvedLocation struct {
	PlaceID  string   `json:"place_id"`
	Name     string   `json:"name,omitempty"`
	Address  string   `json:"address,omitempty"`
	Location *LatLng  `json:"location,omitempty"`
	Types    []string `json:"types,omitempty"`
}

ResolvedLocation is a place candidate for a location string.

type Review

type Review struct {
	Name                           string             `json:"name,omitempty"`
	RelativePublishTimeDescription string             `json:"relative_publish_time_description,omitempty"`
	Text                           *LocalizedText     `json:"text,omitempty"`
	OriginalText                   *LocalizedText     `json:"original_text,omitempty"`
	Rating                         *float64           `json:"rating,omitempty"`
	Author                         *AuthorAttribution `json:"author,omitempty"`
	PublishTime                    string             `json:"publish_time,omitempty"`
	FlagContentURI                 string             `json:"flag_content_uri,omitempty"`
	GoogleMapsURI                  string             `json:"google_maps_uri,omitempty"`
	VisitDate                      *ReviewVisitDate   `json:"visit_date,omitempty"`
}

Review represents a user review of a place.

type ReviewVisitDate

type ReviewVisitDate struct {
	Year  int `json:"year,omitempty"`
	Month int `json:"month,omitempty"`
	Day   int `json:"day,omitempty"`
}

ReviewVisitDate describes the date a reviewer visited a place.

type RouteRequest added in v0.2.0

type RouteRequest struct {
	Query        string  `json:"query"`
	From         string  `json:"from"`
	To           string  `json:"to"`
	Mode         string  `json:"mode,omitempty"`
	RadiusM      float64 `json:"radius_m,omitempty"`
	MaxWaypoints int     `json:"max_waypoints,omitempty"`
	Limit        int     `json:"limit,omitempty"`
	Language     string  `json:"language,omitempty"`
	Region       string  `json:"region,omitempty"`
}

RouteRequest describes a query to search along a route.

type RouteResponse added in v0.2.0

type RouteResponse struct {
	Waypoints []RouteWaypoint `json:"waypoints"`
}

RouteResponse contains sampled waypoints with search results.

type RouteWaypoint added in v0.2.0

type RouteWaypoint struct {
	Location LatLng         `json:"location"`
	Results  []PlaceSummary `json:"results"`
}

RouteWaypoint ties a sampled route location to search results.

type SearchRequest

type SearchRequest struct {
	Query        string        `json:"query"`
	Filters      *Filters      `json:"filters,omitempty"`
	LocationBias *LocationBias `json:"location_bias,omitempty"`
	Limit        int           `json:"limit,omitempty"`
	PageToken    string        `json:"page_token,omitempty"`
	Language     string        `json:"language,omitempty"`
	Region       string        `json:"region,omitempty"`
}

SearchRequest defines a text search with optional filters.

type SearchResponse

type SearchResponse struct {
	Results       []PlaceSummary `json:"results"`
	NextPageToken string         `json:"next_page_token,omitempty"`
}

SearchResponse contains a list of places and optional pagination token.

type ValidationError

type ValidationError struct {
	Field   string
	Message string
}

ValidationError describes an invalid request payload.

func (ValidationError) Error

func (e ValidationError) Error() string

Directories

Path Synopsis
cmd
goplaces command
Package main implements the goplaces CLI entrypoint.
Package main implements the goplaces CLI entrypoint.
internal
cli
Package cli implements the goplaces command-line interface.
Package cli implements the goplaces command-line interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL