github.com/thinwrap/location-go

thinwrap/location-go for Go — unified facade across 6 providers for routing, matrix, geocoding, and isochrone, with built-in polyline utilities. Truly zero deps (net/http only), stateless, BYO *http.Client.

Go constraints

Runtime dependencies
Zero runtime dependencies
BYO HTTP client
injectable *http.Client via the WithHTTPClient option
Provenance
Go module checksum database (sum.golang.org)
Minimum runtime
Go 1.18+
  • Truly zero dependencies — the standard library net/http is the only HTTP surface, and AWS SigV4 (Bedrock) / JWT signing (FCM, APNs) are hand-rolled on crypto/*.
  • Distributed as a Go module with no build step or codegen: the git tag IS the release. The public module proxy serves it directly and integrity is verified through the Go checksum database (sum.golang.org) and your go.sum — there is no separately signed release artifact, and none is needed for `go get`.
  • The default *http.Client never follows redirects — a 3xx surfaces as an error rather than silently re-sending auth headers to another host.

30-second install

go get github.com/thinwrap/location-go

2-minute end-to-end example

Compute a route between two waypoints through any supported provider. The example below uses Mapbox; switching providers means changing the config struct — input and output shape stay identical.

import location "github.com/thinwrap/location-go"

r := location.NewRouting(location.MapboxConfig{AccessToken: os.Getenv("MAPBOX_TOKEN")})

res, err := r.Route(ctx, location.RoutingOptions{
    Waypoints: []location.LatLng{
        {Lat: 37.7749, Lng: -122.4194},
        {Lat: 37.3382, Lng: -121.8863},
    },
})
if err != nil {
    var ce *location.ConnectorError
    if errors.As(err, &ce) { log.Printf("%s: %s", ce.ProviderCode, ce.ProviderMessage) }
    return
}
fmt.Printf("%.1f km, %.0f min\n", res.TotalDistanceMeters/1000, res.TotalDurationSeconds/60)
fmt.Println(res.Polyline) // Google precision-5 encoded

Same code works for all supported routing providers — swap to GoogleConfig, HereConfig,EsriConfig, TomTomConfig, orOsrmConfig{BaseURL: …}. Output normalizes to a single RoutingResult shape across every provider.

Supported providers

6 providers ship with github.com/thinwrap/location-go@1.0.0.
ProviderOperationsAuthREADME
google Google Maps Platformrouting, matrix, geocodingquerydocs
mapbox Mapboxrouting, matrix, geocoding, isochronequerydocs
here HERErouting, matrix, geocoding, isochroneheaderdocs
esri ESRI ArcGISrouting, matrix, geocoding, isochronebearerdocs
tomtom TomTomrouting, matrix, geocoding, isochronequerydocs
osrm OSRM (self-hosted)routing, matrixheaderdocs

Migration paths

Built-in polyline utilities

Every routing connector emits a Google precision-5 encoded polyline onres.Polyline. Decode, re-encode, or convert HERE's flex-polyline / ESRI's path geometry without a third-party library:

points := location.DecodePolyline(res.Polyline)   // []LatLng
reEncoded := location.EncodePolyline(points)       // back to precision-5
here := location.DecodeFlexPolyline("BFoz5...")    // HERE flex-polyline
esri := location.EncodeEsriPaths(paths)            // ESRI-JSON {paths, spatialReference}

The four polyline primitives are the only encode/decode exports — locked at v1.0, no additional module required.

Operation coverage

Provider × operation gaps below are architectural, not bugs:

  • OSRM ships only routing +matrix — geocoding and isochrone are out of scope by design for OSRM.
  • Google does not expose a public isochrone API at v1.0.

Bring your own *http.Client

Inject any client satisfyinginterface{ Do(*http.Request) (*http.Response, error) }via WithHTTPClient. The default client never follows redirects (a 3xx surfaces as an error rather than re-sending auth headers). The wrapper holds no state — the HERE/TomTom async-matrix submit-poll-retrieve cycle stays hidden inside a singleMatrix call.

Cross-language siblings

The TypeScript (/packages/location-ts) and PHP (/packages/location-php) variants ship the same facade shape and provider set — cross-language parity is a design goal, not a hard release gate.

Read more