Documentation
¶
Overview ¶
Package justrouting provides a Go client for the JustRouting API.
A client is created with an API key and, optionally, one or more options:
client := justrouting.NewClient("YOUR_API_KEY",
justrouting.WithHTTPClient(&http.Client{Timeout: 10 * time.Second}))
route, err := client.Routes.Get(ctx, &justrouting.RouteRequest{
Origin: []float64{103.8198, 1.3521},
Destination: []float64{103.9915, 1.3644},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Distance: %.1f km\n", route.Distance/1000)
Coordinates are always [longitude, latitude], the order used by GeoJSON, OSRM and VROOM. All requests take a context.Context and are safe for concurrent use.
Failed calls return an *Error. Use errors.Is with the package sentinels for control flow and errors.As when the status code or raw body is needed:
if errors.Is(err, justrouting.ErrRateLimited) {
// back off and retry later
}
The package has no dependencies outside the standard library.
Example ¶
This is the package quickstart. It compiles as part of the test suite, so the documented usage cannot drift from the API.
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient(
"YOUR_API_KEY",
justrouting.WithHTTPClient(&http.Client{
Timeout: 10 * time.Second,
}),
)
route, err := client.Routes.Get(
context.Background(),
&justrouting.RouteRequest{
Origin: []float64{103.8198, 1.3521},
Destination: []float64{103.9915, 1.3644},
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf(
"Distance: %.1f km\n",
route.Distance/1000,
)
}
Output:
Index ¶
- Constants
- Variables
- type Annotation
- type BBox
- type Client
- type ClientOption
- type Datasource
- type Error
- type GeocodeQuery
- type GeocodeRequest
- type GeocodeResponse
- type GeocodeResult
- type GeocodeService
- type Geometry
- type Health
- type HealthService
- type Intersection
- type Job
- type Lane
- type Leg
- type LineString
- type Maneuver
- type MapMatchingRequest
- type MapMatchingResponse
- type MapMatchingService
- type Match
- type MatrixRequest
- type MatrixResponse
- type MatrixService
- type NearestRequest
- type NearestResponse
- type NearestService
- type OptimizationOptions
- type OptimizationRequest
- type OptimizationService
- type Point
- type Rank
- type Route
- type RouteRequest
- type RouteResponse
- type RouteStep
- type RoutesService
- type Shipment
- type ShipmentStep
- type Solution
- type Step
- type StructuredQuery
- type Summary
- type TimeWindow
- type Timezone
- type Tracepoint
- type TripRequest
- type TripResponse
- type TripService
- type Unassigned
- type Vehicle
- type VehicleRoute
- type Waypoint
Examples ¶
Constants ¶
const ( // Version is the client version, reported in the User-Agent header. Version = "0.3.0" // DefaultBaseURL is the hosted JustRouting API endpoint. DefaultBaseURL = "https://api.justrouting.tech" // DefaultProfile is the routing profile used when a request leaves // Profile empty. DefaultProfile = "driving" )
Variables ¶
var ( ErrUnauthorized = errors.New("justrouting: unauthorized") // ErrRateLimited means the request was throttled. It matches both // per-second throttling and daily quota exhaustion; use // ErrQuotaExceeded to distinguish the latter. ErrRateLimited = errors.New("justrouting: rate limit exceeded") // ErrQuotaExceeded means the plan's daily request quota is used up. // Retrying before the quota resets will not help. ErrQuotaExceeded = errors.New("justrouting: daily quota exceeded") // ErrPlanLimitExceeded means the request is larger than the plan // allows — too many matrix coordinates, jobs, or vehicles. ErrPlanLimitExceeded = errors.New("justrouting: plan limit exceeded") // ErrCrossCountry means the coordinates span more than one country. // Every coordinate in a request must fall within a single country. ErrCrossCountry = errors.New("justrouting: cross-country request not supported") // ErrInvalidCoordinates means a coordinate was malformed, out of range, // or could not be parsed by the API. ErrInvalidCoordinates = errors.New("justrouting: invalid coordinates") // ErrNoRoute means no route exists between the given coordinates. ErrNoRoute = errors.New("justrouting: no route found") // not be reached. This is usually transient. ErrUpstreamUnavailable = errors.New("justrouting: upstream unavailable") // ErrInvalidRequest means the request was rejected before being sent // because required fields were missing or inconsistent. ErrInvalidRequest = errors.New("justrouting: invalid request") )
Sentinel errors for use with errors.Is. They classify an *Error by the condition it represents rather than by an exact message, which keeps calling code stable if the API's wording changes.
Functions ¶
This section is empty.
Types ¶
type Annotation ¶
type Annotation struct {
Distance []float64 `json:"distance,omitempty"`
Duration []float64 `json:"duration,omitempty"`
Speed []float64 `json:"speed,omitempty"`
Weight []float64 `json:"weight,omitempty"`
Nodes []int64 `json:"nodes,omitempty"`
Datasources []int `json:"datasources,omitempty"`
}
Annotation holds per-segment metadata, returned when RouteRequest.Annotations is set.
type BBox ¶ added in v0.2.0
type BBox struct {
Lon1 float64 `json:"lon1"`
Lat1 float64 `json:"lat1"`
Lon2 float64 `json:"lon2"`
Lat2 float64 `json:"lat2"`
}
BBox is a bounding box as [lon1, lat1, lon2, lat2].
type Client ¶
type Client struct {
// Routes computes routes between two or more coordinates.
Routes *RoutesService
// Matrix computes duration and distance matrices.
Matrix *MatrixService
// MapMatching snaps GPS traces onto the road network.
MapMatching *MapMatchingService
// Trip finds the fastest order to visit a set of coordinates.
Trip *TripService
// Nearest finds the road segment closest to a coordinate.
Nearest *NearestService
// Geocode converts addresses into coordinates.
Geocode *GeocodeService
// Optimization solves vehicle routing problems.
Optimization *OptimizationService
// Health reports API and upstream availability.
Health *HealthService
// contains filtered or unexported fields
}
Client is a JustRouting API client. It is safe for concurrent use by multiple goroutines, and should be created once and reused so that underlying HTTP connections are pooled.
func NewClient ¶
func NewClient(apiKey string, opts ...ClientOption) *Client
NewClient returns a Client authenticated with apiKey.
The key is sent as an "Authorization: Bearer" header on every request that needs it. An empty key is allowed but only HealthService.Get will work; every other call fails with ErrUnauthorized before any request is sent.
Invalid options do not panic. The first option error is retained and returned by every subsequent API call, so a misconfigured client surfaces the problem at the first request rather than silently using a default.
type ClientOption ¶
A ClientOption configures a Client. Options are applied by NewClient in the order they are given.
func WithBackoff ¶
func WithBackoff(fn func(attempt int) time.Duration) ClientOption
WithBackoff replaces the delay function used between retries. attempt is 1 for the first retry, 2 for the second, and so on.
The default is exponential backoff with jitter, starting at 500ms and capped at 8s. A Retry-After response header, when present, takes precedence over this function.
func WithBaseURL ¶
func WithBaseURL(raw string) ClientOption
WithBaseURL points the client at a different API endpoint, such as a local development server:
justrouting.WithBaseURL("http://localhost:8080")
The URL must be absolute. Any path is kept as a prefix for every request.
func WithHTTPClient ¶
func WithHTTPClient(hc *http.Client) ClientOption
WithHTTPClient sets the HTTP client used for all requests. Use it to control timeouts, proxies, or transport-level instrumentation:
justrouting.NewClient(key, justrouting.WithHTTPClient(&http.Client{
Timeout: 10 * time.Second,
}))
The timeout on the supplied client covers a single HTTP attempt, not the whole retry sequence; use a context deadline to bound the total call.
func WithMaxRetries ¶
func WithMaxRetries(n int) ClientOption
WithMaxRetries sets how many times a failed request is retried, on top of the initial attempt. The default is 2. Pass 0 to disable retries.
Only rate-limit (429), server (5xx) and transport errors are retried; other 4xx responses are returned immediately.
func WithUserAgent ¶
func WithUserAgent(ua string) ClientOption
WithUserAgent overrides the User-Agent header. Identifying your application helps when diagnosing traffic against the API.
type Datasource ¶ added in v0.2.0
type Datasource struct {
Sourcename string `json:"sourcename"`
Attribution string `json:"attribution"`
License string `json:"license"`
URL string `json:"url"`
}
Datasource credits the data provider of a GeocodeResult.
type Error ¶
type Error struct {
// StatusCode is the HTTP status of the response.
StatusCode int
// Message is the human-readable reason reported by the API.
Message string
// OSRMCode is the routing engine's status code, such as "NoRoute" or
// "InvalidValue". Empty when the error did not come from the routing
// engine.
OSRMCode string
// VROOMCode is the optimization engine's non-zero status code. Zero
// when the error did not come from the optimization engine.
VROOMCode int
// Body is the raw response body, truncated to a sane limit. Useful for
// logging responses this package does not model.
Body []byte
}
Error describes a failed API call.
It is returned whenever the API responds with a non-2xx status, and also when a 2xx response carries an in-body failure code — the routing and optimization engines can both report errors alongside HTTP 200.
Match it with errors.Is against the package sentinels, or retrieve it with errors.As when the status code or raw body is needed:
var apiErr *justrouting.Error
if errors.As(err, &apiErr) {
log.Printf("status %d: %s", apiErr.StatusCode, apiErr.Message)
}
Example ¶
Failures are classified with sentinel errors, so callers never match on message text.
package main
import (
"context"
"errors"
"fmt"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
_, err := client.Routes.Get(context.Background(), &justrouting.RouteRequest{
Origin: justrouting.Point{103.8198, 1.3521},
Destination: justrouting.Point{101.6869, 3.1390},
})
switch {
case err == nil:
fmt.Println("ok")
case errors.Is(err, justrouting.ErrCrossCountry):
fmt.Println("all coordinates must be in the same country")
case errors.Is(err, justrouting.ErrQuotaExceeded):
fmt.Println("daily quota used up; retrying will not help")
case errors.Is(err, justrouting.ErrRateLimited):
fmt.Println("throttled; the client already retried")
case errors.Is(err, justrouting.ErrNoRoute):
fmt.Println("no road connects these points")
default:
// Reach for the concrete type when the status or raw body matters.
var apiErr *justrouting.Error
if errors.As(err, &apiErr) {
fmt.Printf("HTTP %d: %s\n", apiErr.StatusCode, apiErr.Message)
}
}
}
Output:
type GeocodeQuery ¶ added in v0.2.0
type GeocodeQuery struct {
// Text is the free-text query as received by the API.
Text string `json:"text"`
// Parsed is the API's structured interpretation of Text. Its shape is
// not guaranteed, so it is preserved as raw JSON.
Parsed json.RawMessage `json:"parsed"`
}
GeocodeQuery echoes how the API interpreted the request.
type GeocodeRequest ¶ added in v0.2.0
type GeocodeRequest struct {
// Text is the free-form address to search for, such as
// "Marina Bay Sands, Singapore". Mutually exclusive with Structured.
Text string
// Structured is an address given as typed components. Mutually
// exclusive with Text.
Structured *StructuredQuery
// Limit caps the number of results. The API defaults to 5.
Limit int
// Offset skips the first Offset results before applying Limit.
Offset int
// Filters restrict results, for example "countrycode:sg". Each entry
// is sent as its own filter parameter; the API applies all of them.
Filters []string
// Bias steers results toward a location, for example
// "proximity:103.8,1.3". It is forwarded verbatim.
Bias string
// Type restricts results to a feature type such as "street" or "city".
Type string
// Lang requests results in a language, such as "en".
Lang string
}
GeocodeRequest describes a forward-geocoding search. Exactly one of Text and Structured must be set.
type GeocodeResponse ¶ added in v0.2.0
type GeocodeResponse struct {
// Results are ordered best first. Empty when nothing matches.
Results []*GeocodeResult `json:"results"`
// Query echoes how the API interpreted the request, when returned.
Query *GeocodeQuery `json:"query"`
}
GeocodeResponse is the result of a forward-geocoding search.
type GeocodeResult ¶ added in v0.2.0
type GeocodeResult struct {
// Datasource credits the data provider.
Datasource Datasource `json:"datasource,omitempty"`
Housenumber string `json:"housenumber,omitempty"`
Street string `json:"street,omitempty"`
Suburb string `json:"suburb,omitempty"`
City string `json:"city,omitempty"`
County string `json:"county,omitempty"`
State string `json:"state,omitempty"`
StateCode string `json:"state_code,omitempty"`
Postcode string `json:"postcode,omitempty"`
Country string `json:"country,omitempty"`
CountryCode string `json:"country_code,omitempty"`
Lon float64 `json:"lon"`
Lat float64 `json:"lat"`
Formatted string `json:"formatted,omitempty"`
AddressLine1 string `json:"address_line1,omitempty"`
AddressLine2 string `json:"address_line2,omitempty"`
ResultType string `json:"result_type,omitempty"`
// Rank scores the result's relevance and match confidence.
Rank Rank `json:"rank,omitempty"`
// Timezone is the result's time zone with standard- and daylight-time
// offsets.
Timezone Timezone `json:"timezone,omitempty"`
// PlaceID is the upstream's opaque identifier for the place.
PlaceID string `json:"place_id,omitempty"`
Category string `json:"category,omitempty"`
PlusCode string `json:"plus_code,omitempty"`
Name string `json:"name,omitempty"`
// BBox is the result's bounding box as [lon1, lat1, lon2, lat2].
BBox BBox `json:"bbox,omitempty"`
// Distance is the metres from the bias location, present only when
// Bias is set.
Distance float64 `json:"distance,omitempty"`
}
GeocodeResult is one matching place.
func (*GeocodeResult) Location ¶ added in v0.2.0
func (r *GeocodeResult) Location() Point
Location returns the result's position as a Point, in the package's usual [longitude, latitude] order.
type GeocodeService ¶ added in v0.2.0
type GeocodeService struct {
// contains filtered or unexported fields
}
GeocodeService converts addresses into coordinates.
func (*GeocodeService) Search ¶ added in v0.2.0
func (s *GeocodeService) Search(ctx context.Context, req *GeocodeRequest) (*GeocodeResponse, error)
Search geocodes req and returns matching places, ordered best first.
results, err := client.Geocode.Search(ctx, &justrouting.GeocodeRequest{
Text: "Marina Bay Sands, Singapore",
})
fmt.Println(results.Results[0].Formatted)
A response with an empty Results list means nothing matched; it is not an error.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
results, err := client.Geocode.Search(context.Background(), &justrouting.GeocodeRequest{
Text: "Marina Bay Sands, Singapore",
})
if err != nil {
log.Fatal(err)
}
for _, r := range results.Results {
fmt.Printf("%s (%.4f, %.4f)\n", r.Formatted, r.Lon, r.Lat)
}
}
Output:
type Geometry ¶
type Geometry struct {
// contains filtered or unexported fields
}
Geometry holds a route geometry. OSRM encodes it either as an encoded polyline string (geometries=polyline, the default, or polyline6) or as a GeoJSON LineString object (geometries=geojson). Geometry preserves whichever form the server sent; read it with Geometry.Polyline or Geometry.GeoJSON.
func (Geometry) GeoJSON ¶
func (g Geometry) GeoJSON() (*LineString, error)
GeoJSON returns the geometry as a GeoJSON LineString. It reports an error if the request used the default polyline encoding.
func (Geometry) IsZero ¶
IsZero reports whether the server omitted the geometry, which happens when a request sets overview=false.
func (Geometry) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (Geometry) Polyline ¶
Polyline returns the geometry as an encoded polyline string. It reports an error if the request asked for GeoJSON instead.
func (Geometry) Raw ¶
func (g Geometry) Raw() json.RawMessage
Raw returns the geometry exactly as the server encoded it.
func (*Geometry) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type Health ¶
type Health struct {
// Status is "ok" when every upstream is reachable, otherwise
// "degraded".
Status string `json:"status"`
// Timestamp is when the check ran, in RFC 3339 format.
Timestamp string `json:"timestamp"`
// Upstreams maps each routing engine to its reachability.
Upstreams map[string]bool `json:"upstreams"`
}
Health is the API's self-reported status.
type HealthService ¶
type HealthService struct {
// contains filtered or unexported fields
}
HealthService reports API availability.
type Intersection ¶
type Intersection struct {
Location Point `json:"location"`
Bearings []int `json:"bearings"`
Entry []bool `json:"entry"`
In *int `json:"in,omitempty"`
Out *int `json:"out,omitempty"`
Lanes []Lane `json:"lanes,omitempty"`
}
Intersection is a junction passed during a Step.
type Job ¶
type Job struct {
// ID identifies the job in the solution. It must be unique.
ID int `json:"id"`
// Location is where the job happens, as [longitude, latitude].
Location Point `json:"location"`
// Setup is fixed preparation time in seconds.
Setup int `json:"setup,omitempty"`
// Service is time spent on site, in seconds.
Service int `json:"service,omitempty"`
// Delivery is the amount unloaded here, matching vehicle Capacity.
Delivery []int `json:"delivery,omitempty"`
// Pickup is the amount loaded here, matching vehicle Capacity.
Pickup []int `json:"pickup,omitempty"`
// Skills lists capabilities a vehicle must have to serve this job.
Skills []int `json:"skills,omitempty"`
// Priority ranks this job from 0 to 100 when not everything fits.
Priority int `json:"priority,omitempty"`
// TimeWindows constrains when the job may be served.
TimeWindows []TimeWindow `json:"time_windows,omitempty"`
// Description is an opaque label echoed back in the solution.
Description string `json:"description,omitempty"`
}
Job is a task carried out at a single location.
type Lane ¶
Lane describes a turn lane at an Intersection.
type Leg ¶
type Leg struct {
Distance float64 `json:"distance"`
Duration float64 `json:"duration"`
Weight float64 `json:"weight"`
Summary string `json:"summary"`
Steps []*Step `json:"steps,omitempty"`
Annotation *Annotation `json:"annotation,omitempty"`
}
Leg is the portion of a route between two consecutive waypoints.
type LineString ¶
LineString is a GeoJSON LineString geometry.
type Maneuver ¶
type Maneuver struct {
Location Point `json:"location"`
BearingBefore int `json:"bearing_before"`
BearingAfter int `json:"bearing_after"`
Type string `json:"type"`
Modifier string `json:"modifier,omitempty"`
Exit int `json:"exit,omitempty"`
}
Maneuver describes the action taken at the start of a Step.
type MapMatchingRequest ¶ added in v0.3.0
type MapMatchingRequest struct {
// Coordinates is the trace to match, in chronological order.
Coordinates []Point
// Timestamps are UNIX seconds for each coordinate. When set, its length
// must equal the number of coordinates.
Timestamps []int64
// Radiuses are the maximum distance in metres each coordinate may
// snap, one value per coordinate. The engine's default snap distance
// is only a few metres, so GPS points further from the road need this
// set.
Radiuses []float64
// Gaps controls how a trace with gaps is matched: "split" (the
// default) or "ignore".
Gaps string
// Tidy drops tracepoints that cannot be matched from the response.
Tidy bool
// Waypoints selects which coordinates to use as waypoints, by index
// into Coordinates. Empty means all of them.
Waypoints []int
// Snapping controls edge snapping: "default" or "any".
Snapping string
// Profile selects the routing profile. Defaults to [DefaultProfile].
Profile string
// Steps requests turn-by-turn instructions on each leg.
Steps bool
// Annotations requests per-segment metadata. Valid values include
// "duration", "distance", "speed" and "nodes".
Annotations []string
// Geometries selects the geometry encoding: "polyline" (the default),
// "polyline6" or "geojson". See [Geometry].
Geometries string
// Overview controls geometry detail: "simplified" (the default),
// "full" or "false" to omit it.
Overview string
// Exclude lists road classes to avoid, such as "motorway" or "ferry".
// Supported values depend on the profile.
Exclude []string
}
MapMatchingRequest describes a map-matching query. Coordinates is required and must hold at least two points in chronological order.
The number of coordinates is capped by the account plan; exceeding it returns an error matching ErrPlanLimitExceeded.
type MapMatchingResponse ¶ added in v0.3.0
type MapMatchingResponse struct {
// Code is the engine status, "Ok" on success.
Code string `json:"code"`
// Message explains a non-Ok Code.
Message string `json:"message,omitempty"`
// Tracepoints are the input coordinates snapped to the road network,
// aligned with req.Coordinates. An entry is nil when that coordinate
// could not be matched.
Tracepoints []*Tracepoint `json:"tracepoints"`
// Matchings are the routes assembled from the trace, best first.
Matchings []*Match `json:"matchings"`
}
MapMatchingResponse is the full result of a map-matching query.
type MapMatchingService ¶ added in v0.3.0
type MapMatchingService struct {
// contains filtered or unexported fields
}
MapMatchingService snaps a noisy GPS trace onto the road network and assembles the driven route.
func (*MapMatchingService) Get ¶ added in v0.3.0
func (s *MapMatchingService) Get(ctx context.Context, req *MapMatchingRequest) (*Match, error)
Get returns the best matching for req.
match, err := client.MapMatching.Get(ctx, &justrouting.MapMatchingRequest{
Coordinates: trace, // GPS points, in order
})
fmt.Printf("%.0f%% confidence, %.1f km\n", match.Confidence*100, match.Distance/1000)
It returns an error with OSRMCode "NoMatch" when no coordinate can be matched. Use MapMatchingService.GetAll for the snapped tracepoints.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
// A noisy GPS trace, in chronological order.
trace := []justrouting.Point{
{103.8198, 1.3521},
{103.8514, 1.2897},
{103.9915, 1.3644},
}
match, err := client.MapMatching.Get(context.Background(), &justrouting.MapMatchingRequest{
Coordinates: trace,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%.0f%% confidence, %.1f km\n", match.Confidence*100, match.Distance/1000)
}
Output:
func (*MapMatchingService) GetAll ¶ added in v0.3.0
func (s *MapMatchingService) GetAll(ctx context.Context, req *MapMatchingRequest) (*MapMatchingResponse, error)
GetAll returns every matching the engine produced for req, along with the snapped tracepoints.
type Match ¶ added in v0.3.0
type Match struct {
Route
// Confidence is the engine's trust in the match, from 0 to 1.
Confidence float64 `json:"confidence"`
}
Match is one route assembled from a trace. It embeds Route, adding the engine's confidence in the match.
type MatrixRequest ¶
type MatrixRequest struct {
// Coordinates are the points to measure between.
Coordinates []Point
// Sources selects which coordinates act as row origins, by index into
// Coordinates. Empty means all of them.
Sources []int
// Destinations selects which coordinates act as column targets, by
// index into Coordinates. Empty means all of them.
Destinations []int
// Annotations selects which matrices to compute: "duration",
// "distance", or both. Defaults to both.
Annotations []string
// Profile selects the routing profile. Defaults to [DefaultProfile].
Profile string
}
MatrixRequest describes a matrix query. Coordinates is required and must hold at least two points.
By default every coordinate is used as both a source and a destination, producing an NxN matrix. Set Sources and/or Destinations to compute a rectangular subset instead, which is considerably cheaper.
The number of coordinates is capped by the account plan; exceeding it returns an error matching ErrPlanLimitExceeded.
type MatrixResponse ¶
type MatrixResponse struct {
// Code is the engine status, "Ok" on success.
Code string `json:"code"`
// Message explains a non-Ok Code.
Message string `json:"message,omitempty"`
// Durations holds travel times in seconds, indexed [source][destination].
Durations [][]*float64 `json:"durations,omitempty"`
// Distances holds travel distances in metres, indexed [source][destination].
Distances [][]*float64 `json:"distances,omitempty"`
// Sources are the source coordinates snapped to the road network.
Sources []*Waypoint `json:"sources"`
// Destinations are the destination coordinates snapped to the road network.
Destinations []*Waypoint `json:"destinations"`
}
MatrixResponse holds the computed matrices.
Entries are pointers because the engine reports an unreachable pair as null, which must stay distinguishable from a genuine zero. Prefer the MatrixResponse.Duration and MatrixResponse.Distance accessors.
type MatrixService ¶
type MatrixService struct {
// contains filtered or unexported fields
}
MatrixService computes travel duration and distance between many coordinates at once.
func (*MatrixService) Get ¶
func (s *MatrixService) Get(ctx context.Context, req *MatrixRequest) (*MatrixResponse, error)
Get computes the duration and distance matrices for req.
m, err := client.Matrix.Get(ctx, &justrouting.MatrixRequest{
Coordinates: []justrouting.Point{depot, stopA, stopB},
})
if secs, ok := m.Duration(0, 1); ok {
fmt.Printf("depot -> stopA: %.0f min", secs/60)
}
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
depot := justrouting.Point{103.8198, 1.3521}
stops := []justrouting.Point{
{103.8514, 1.2897},
{103.9915, 1.3644},
}
m, err := client.Matrix.Get(context.Background(), &justrouting.MatrixRequest{
Coordinates: append([]justrouting.Point{depot}, stops...),
// Only the depot-to-stop row is needed, which is cheaper than
// computing the full square matrix.
Sources: []int{0},
Destinations: []int{1, 2},
})
if err != nil {
log.Fatal(err)
}
for j := range stops {
if seconds, ok := m.Duration(0, j); ok {
fmt.Printf("stop %d: %.0f min\n", j+1, seconds/60)
} else {
fmt.Printf("stop %d: unreachable\n", j+1)
}
}
}
Output:
type NearestRequest ¶ added in v0.3.0
type NearestRequest struct {
// Coordinate is the point to snap, as [longitude, latitude].
Coordinate Point
// Number is how many nearby segments to return, ordered by distance.
// Defaults to 1.
Number int
// Profile selects the routing profile. Defaults to [DefaultProfile].
Profile string
// Exclude lists road classes to avoid, such as "motorway" or "ferry".
// Supported values depend on the profile.
Exclude []string
}
NearestRequest describes a nearest-segment query. Coordinate is required.
type NearestResponse ¶ added in v0.3.0
type NearestResponse struct {
// Code is the engine status, "Ok" on success.
Code string `json:"code"`
// Message explains a non-Ok Code.
Message string `json:"message,omitempty"`
// Waypoints are the segments nearest to the coordinate, best first.
Waypoints []*Waypoint `json:"waypoints"`
}
NearestResponse is the result of a nearest-segment query.
type NearestService ¶ added in v0.3.0
type NearestService struct {
// contains filtered or unexported fields
}
NearestService finds the road segments closest to a coordinate.
func (*NearestService) Get ¶ added in v0.3.0
func (s *NearestService) Get(ctx context.Context, req *NearestRequest) (*Waypoint, error)
Get returns the road segment closest to req.Coordinate.
wp, err := client.Nearest.Get(ctx, &justrouting.NearestRequest{
Coordinate: []float64{103.8198, 1.3521},
})
fmt.Printf("snapped to %s, %.0f m away\n", wp.Name, wp.Distance)
Use NearestService.GetAll for the second-, third-, ... nearest segments.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
wp, err := client.Nearest.Get(context.Background(), &justrouting.NearestRequest{
Coordinate: justrouting.Point{103.8198, 1.3521},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s, %.0f m away\n", wp.Name, wp.Distance)
}
Output:
func (*NearestService) GetAll ¶ added in v0.3.0
func (s *NearestService) GetAll(ctx context.Context, req *NearestRequest) (*NearestResponse, error)
GetAll returns up to req.Number road segments near req.Coordinate, best first.
type OptimizationOptions ¶
type OptimizationOptions struct {
// Geometry requests a road-following geometry for each route. It costs
// extra computation, so it is off by default.
Geometry bool `json:"g,omitempty"`
}
OptimizationOptions tunes solver behaviour.
type OptimizationRequest ¶
type OptimizationRequest struct {
// Vehicles is the available fleet.
Vehicles []Vehicle `json:"vehicles"`
// Jobs are single-location tasks.
Jobs []Job `json:"jobs,omitempty"`
// Shipments are pickup-and-delivery pairs handled by one vehicle.
Shipments []Shipment `json:"shipments,omitempty"`
// Options tunes the solver.
Options *OptimizationOptions `json:"options,omitempty"`
}
OptimizationRequest describes a vehicle routing problem. At least one vehicle and at least one job or shipment are required.
Fleet and task counts are capped by the account plan; exceeding either returns an error matching ErrPlanLimitExceeded.
type OptimizationService ¶
type OptimizationService struct {
// contains filtered or unexported fields
}
OptimizationService solves vehicle routing problems: given a fleet and a set of tasks, it assigns tasks to vehicles and orders each vehicle's stops.
func (*OptimizationService) Solve ¶
func (s *OptimizationService) Solve(ctx context.Context, req *OptimizationRequest) (*Solution, error)
Solve assigns the request's tasks to its vehicles and orders each route.
solution, err := client.Optimization.Solve(ctx, &justrouting.OptimizationRequest{
Vehicles: []justrouting.Vehicle{{ID: 1, Start: depot, End: depot}},
Jobs: []justrouting.Job{
{ID: 1, Location: stopA},
{ID: 2, Location: stopB},
},
})
All coordinates in a request must lie within a single country; otherwise the call fails with an error matching ErrCrossCountry.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
depot := justrouting.Point{103.8198, 1.3521}
solution, err := client.Optimization.Solve(context.Background(), &justrouting.OptimizationRequest{
Vehicles: []justrouting.Vehicle{
{ID: 1, Start: depot, End: depot, Capacity: []int{4}},
},
Jobs: []justrouting.Job{
{ID: 1, Location: justrouting.Point{103.8514, 1.2897}, Delivery: []int{1}, Service: 300},
{ID: 2, Location: justrouting.Point{103.9915, 1.3644}, Delivery: []int{2}, Service: 300},
},
})
if err != nil {
log.Fatal(err)
}
for _, route := range solution.Routes {
fmt.Printf("vehicle %d serves %d stops\n", route.Vehicle, len(route.Steps))
}
fmt.Printf("%d task(s) unassigned\n", len(solution.Unassigned))
}
Output:
type Point ¶
type Point []float64
Point is a geographic coordinate expressed as [longitude, latitude] — the order used by GeoJSON, OSRM and VROOM, and the reverse of the "lat, lng" convention used by most map UIs.
Point is defined over []float64, so an ordinary slice literal works anywhere a Point is expected:
Origin: []float64{103.8198, 1.3521} // Singapore
func (Point) String ¶
String formats p as "longitude,latitude" using the shortest representation that round-trips exactly.
func (Point) Validate ¶
Validate reports whether p is a well-formed [longitude, latitude] pair within the valid ranges. It wraps ErrInvalidCoordinates.
type Rank ¶ added in v0.2.0
type Rank struct {
Importance float64 `json:"importance"`
Popularity float64 `json:"popularity"`
Confidence float64 `json:"confidence"`
ConfidenceCityLevel float64 `json:"confidence_city_level"`
ConfidenceStreetLevel float64 `json:"confidence_street_level"`
MatchType string `json:"match_type"`
}
Rank scores a GeocodeResult's relevance and match confidence.
type Route ¶
type Route struct {
// Distance is the route length in metres.
Distance float64 `json:"distance"`
// Duration is the estimated travel time in seconds.
Duration float64 `json:"duration"`
// Weight is the value the engine minimised, in WeightName units.
Weight float64 `json:"weight"`
// WeightName names the optimisation metric, such as "routability".
WeightName string `json:"weight_name"`
// Geometry is the route's shape.
Geometry Geometry `json:"geometry"`
// Legs holds one entry per consecutive pair of waypoints.
Legs []*Leg `json:"legs"`
}
Route is a single path through the road network.
type RouteRequest ¶
type RouteRequest struct {
// Origin is where the route starts, as [longitude, latitude].
Origin Point
// Destination is where the route ends, as [longitude, latitude].
Destination Point
// Waypoints are intermediate stops, visited in the order given.
Waypoints []Point
// Profile selects the routing profile. Defaults to [DefaultProfile].
Profile string
// Alternatives requests up to this many alternative routes. They are
// returned by GetAll; Get always yields the best route. The engine may
// return fewer, or none, if no reasonable alternative exists.
Alternatives int
// Steps requests turn-by-turn instructions on each leg.
Steps bool
// Annotations requests per-segment metadata. Valid values include
// "duration", "distance", "speed" and "nodes".
Annotations []string
// Geometries selects the geometry encoding: "polyline" (the default),
// "polyline6" or "geojson". See [Geometry].
Geometries string
// Overview controls geometry detail: "simplified" (the default),
// "full" or "false" to omit it.
Overview string
// ContinueStraight forces or forbids continuing straight at the first
// waypoint. Nil leaves the decision to the engine.
ContinueStraight *bool
// Exclude lists road classes to avoid, such as "motorway" or "ferry".
// Supported values depend on the profile.
Exclude []string
}
RouteRequest describes a routing query. Origin and Destination are required; every other field is optional.
type RouteResponse ¶
type RouteResponse struct {
// Code is the engine status, "Ok" on success.
Code string `json:"code"`
// Message explains a non-Ok Code.
Message string `json:"message,omitempty"`
// Routes are ordered best first.
Routes []*Route `json:"routes"`
// Waypoints are the input coordinates snapped to the road network.
Waypoints []*Waypoint `json:"waypoints"`
}
RouteResponse is the full result of a routing query.
type RouteStep ¶
type RouteStep struct {
// Type is one of "start", "job", "pickup", "delivery", "break" or "end".
Type string `json:"type"`
// Location is where the stop happens.
Location Point `json:"location,omitempty"`
// ID is the task ID, for task steps.
ID int `json:"id,omitempty"`
// Job is the job ID, for job steps.
Job int `json:"job,omitempty"`
Setup int `json:"setup"`
Service int `json:"service"`
WaitingTime int `json:"waiting_time"`
// Arrival is the arrival time in seconds.
Arrival int `json:"arrival"`
Duration int `json:"duration"`
Distance int `json:"distance,omitempty"`
// Load is the vehicle load after this stop.
Load []int `json:"load,omitempty"`
Description string `json:"description,omitempty"`
}
RouteStep is a single stop on a VehicleRoute.
type RoutesService ¶
type RoutesService struct {
// contains filtered or unexported fields
}
RoutesService computes the fastest route between coordinates.
func (*RoutesService) Get ¶
func (s *RoutesService) Get(ctx context.Context, req *RouteRequest) (*Route, error)
Get returns the best route for req.
route, err := client.Routes.Get(ctx, &justrouting.RouteRequest{
Origin: []float64{103.8198, 1.3521},
Destination: []float64{103.9915, 1.3644},
})
fmt.Printf("%.1f km", route.Distance/1000)
It returns an error matching ErrNoRoute when the coordinates cannot be connected. Use RoutesService.GetAll for alternatives and snapped waypoints.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
route, err := client.Routes.Get(context.Background(), &justrouting.RouteRequest{
Origin: justrouting.Point{103.8198, 1.3521},
Destination: justrouting.Point{103.9915, 1.3644},
Waypoints: []justrouting.Point{{103.8514, 1.2897}},
Overview: "full",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%.1f km in %.0f min\n", route.Distance/1000, route.Duration/60)
if polyline, err := route.Geometry.Polyline(); err == nil {
fmt.Println("geometry:", polyline)
}
}
Output:
func (*RoutesService) GetAll ¶
func (s *RoutesService) GetAll(ctx context.Context, req *RouteRequest) (*RouteResponse, error)
GetAll returns every route the engine produced for req, along with the snapped input waypoints.
type Shipment ¶
type Shipment struct {
Pickup ShipmentStep `json:"pickup"`
Delivery ShipmentStep `json:"delivery"`
// Amount is the load carried between the two steps.
Amount []int `json:"amount,omitempty"`
// Skills lists capabilities a vehicle must have.
Skills []int `json:"skills,omitempty"`
// Priority ranks this shipment from 0 to 100.
Priority int `json:"priority,omitempty"`
}
Shipment is a pickup and a delivery that must be served in order by the same vehicle.
type ShipmentStep ¶
type ShipmentStep struct {
ID int `json:"id"`
Location Point `json:"location"`
Setup int `json:"setup,omitempty"`
Service int `json:"service,omitempty"`
TimeWindows []TimeWindow `json:"time_windows,omitempty"`
Description string `json:"description,omitempty"`
}
ShipmentStep is one half of a Shipment.
type Solution ¶
type Solution struct {
// Code is the engine status, 0 on success.
Code int `json:"code"`
// Error explains a non-zero Code.
Error string `json:"error,omitempty"`
// Summary aggregates the whole solution.
Summary Summary `json:"summary"`
// Routes holds one entry per vehicle that was used.
Routes []*VehicleRoute `json:"routes"`
// Unassigned lists tasks that could not be served.
Unassigned []*Unassigned `json:"unassigned"`
}
Solution is the result of an optimization run.
type Step ¶
type Step struct {
Distance float64 `json:"distance"`
Duration float64 `json:"duration"`
Weight float64 `json:"weight"`
Geometry Geometry `json:"geometry"`
Name string `json:"name"`
Ref string `json:"ref,omitempty"`
Mode string `json:"mode"`
Maneuver Maneuver `json:"maneuver"`
Intersections []*Intersection `json:"intersections,omitempty"`
}
Step is a single turn-by-turn instruction, returned when RouteRequest.Steps is set.
type StructuredQuery ¶ added in v0.2.0
type StructuredQuery struct {
Name string
// Housenumber is lowercased to match the upstream parameter name.
Housenumber string
Street string
Postcode string
City string
State string
Country string
}
StructuredQuery is an address expressed as typed fields. Only the fields that are set are sent.
type Summary ¶
type Summary struct {
Cost int `json:"cost"`
Routes int `json:"routes"`
Unassigned int `json:"unassigned"`
Delivery []int `json:"delivery,omitempty"`
Pickup []int `json:"pickup,omitempty"`
Setup int `json:"setup"`
Service int `json:"service"`
Duration int `json:"duration"`
WaitingTime int `json:"waiting_time"`
Priority int `json:"priority"`
Distance int `json:"distance,omitempty"`
}
Summary aggregates the cost and time of a whole Solution.
type TimeWindow ¶
type TimeWindow [2]int
TimeWindow is an inclusive [start, end] pair, in seconds, relative to the same origin used by the rest of the request.
type Timezone ¶ added in v0.2.0
type Timezone struct {
Name string `json:"name"`
OffsetSTD string `json:"offset_STD"`
OffsetSTDSeconds int `json:"offset_STD_seconds"`
OffsetDST string `json:"offset_DST"`
OffsetDSTSeconds int `json:"offset_DST_seconds"`
AbbreviationSTD string `json:"abbreviation_STD"`
AbbreviationDST string `json:"abbreviation_DST"`
}
Timezone is a GeocodeResult's time zone with standard- and daylight-time offsets.
type Tracepoint ¶ added in v0.3.0
type Tracepoint struct {
// AlternativesCount is how many other plausible matches exist for this
// tracepoint.
AlternativesCount int `json:"alternatives_count,omitempty"`
// WaypointIndex is the index of this point within the matched route's
// waypoints.
WaypointIndex int `json:"waypoint_index,omitempty"`
// MatchingsIndex identifies which entry of Matchings this tracepoint
// belongs to.
MatchingsIndex int `json:"matchings_index,omitempty"`
// Distance is the metres between the input coordinate and Location.
Distance float64 `json:"distance"`
// Name is the street the coordinate snapped to, if known.
Name string `json:"name"`
// Location is the snapped position.
Location Point `json:"location"`
// Hint is an opaque token that can speed up subsequent requests.
Hint string `json:"hint,omitempty"`
}
Tracepoint is one input coordinate snapped to the road network.
type TripRequest ¶ added in v0.3.0
type TripRequest struct {
// Coordinates are the points to visit, in any order.
Coordinates []Point
// Roundtrip makes the trip end where it started. Nil leaves the
// engine default, which is true.
Roundtrip *bool
// Source pins where the trip starts: "any" (the default) or "first".
Source string
// Destination pins where the trip ends: "any" (the default) or
// "last".
Destination string
// Profile selects the routing profile. Defaults to [DefaultProfile].
Profile string
// Steps requests turn-by-turn instructions on each leg.
Steps bool
// Annotations requests per-segment metadata. Valid values include
// "duration", "distance", "speed" and "nodes".
Annotations []string
// Geometries selects the geometry encoding: "polyline" (the default),
// "polyline6" or "geojson". See [Geometry].
Geometries string
// Overview controls geometry detail: "simplified" (the default),
// "full" or "false" to omit it.
Overview string
// Exclude lists road classes to avoid, such as "motorway" or "ferry".
// Supported values depend on the profile.
Exclude []string
}
TripRequest describes a trip query. Coordinates is required and must hold at least two points.
The engine solves the travelling-salesman problem with a greedy heuristic: the returned trip visits every coordinate once, in whatever order is fastest. The number of coordinates is capped by the account plan; exceeding it returns an error matching ErrPlanLimitExceeded.
type TripResponse ¶ added in v0.3.0
type TripResponse struct {
// Code is the engine status, "Ok" on success.
Code string `json:"code"`
// Message explains a non-Ok Code.
Message string `json:"message,omitempty"`
// Trips are the candidate round trips, best first.
Trips []*Route `json:"trips"`
// Waypoints are the input coordinates snapped to the road network, in
// the order the trip visits them.
Waypoints []*Waypoint `json:"waypoints"`
}
TripResponse is the full result of a trip query.
type TripService ¶ added in v0.3.0
type TripService struct {
// contains filtered or unexported fields
}
TripService finds the fastest order to visit a set of coordinates.
func (*TripService) Get ¶ added in v0.3.0
func (s *TripService) Get(ctx context.Context, req *TripRequest) (*Route, error)
Get returns the best trip for req.
trip, err := client.Trip.Get(ctx, &justrouting.TripRequest{
Coordinates: []justrouting.Point{depot, stopA, stopB},
})
fmt.Printf("fastest order covers %.1f km\n", trip.Distance/1000)
The waypoints in TripResponse.Waypoints are ordered as visited. Use TripService.GetAll to retrieve them.
Example ¶
package main
import (
"context"
"fmt"
"log"
justrouting "github.com/justrouting/go-client"
)
func main() {
client := justrouting.NewClient("YOUR_API_KEY")
depot := justrouting.Point{103.8198, 1.3521}
trip, err := client.Trip.Get(context.Background(), &justrouting.TripRequest{
Coordinates: []justrouting.Point{
depot,
{103.8514, 1.2897},
{103.9915, 1.3644},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%.1f km in %.0f min\n", trip.Distance/1000, trip.Duration/60)
}
Output:
func (*TripService) GetAll ¶ added in v0.3.0
func (s *TripService) GetAll(ctx context.Context, req *TripRequest) (*TripResponse, error)
GetAll returns every trip the engine produced for req, along with the snapped waypoints in visiting order.
type Unassigned ¶
type Unassigned struct {
ID int `json:"id"`
Type string `json:"type,omitempty"`
Location Point `json:"location,omitempty"`
Description string `json:"description,omitempty"`
}
Unassigned is a task the solver could not fit into any route.
type Vehicle ¶
type Vehicle struct {
// ID identifies the vehicle in the solution. It must be unique.
ID int `json:"id"`
// Profile selects the routing profile for this vehicle.
Profile string `json:"profile,omitempty"`
// Start is where the vehicle begins, as [longitude, latitude]. Omit
// for a vehicle that may start anywhere.
Start Point `json:"start,omitempty"`
// End is where the vehicle must finish. Omit to end anywhere.
End Point `json:"end,omitempty"`
// Capacity is a multidimensional capacity vector. Its length must
// match the Delivery and Pickup vectors on tasks.
Capacity []int `json:"capacity,omitempty"`
// Skills lists capabilities this vehicle provides.
Skills []int `json:"skills,omitempty"`
// TimeWindow bounds when the vehicle is available.
TimeWindow *TimeWindow `json:"time_window,omitempty"`
// MaxTasks caps how many tasks the vehicle may be assigned.
MaxTasks int `json:"max_tasks,omitempty"`
// Description is an opaque label echoed back in the solution.
Description string `json:"description,omitempty"`
}
Vehicle is one member of the fleet.
type VehicleRoute ¶
type VehicleRoute struct {
// Vehicle is the ID of the vehicle serving this route.
Vehicle int `json:"vehicle"`
Cost int `json:"cost"`
Setup int `json:"setup"`
Service int `json:"service"`
Duration int `json:"duration"`
WaitingTime int `json:"waiting_time"`
Priority int `json:"priority"`
Distance int `json:"distance,omitempty"`
Delivery []int `json:"delivery,omitempty"`
Pickup []int `json:"pickup,omitempty"`
// Geometry is an encoded polyline, present only when
// [OptimizationOptions.Geometry] was set.
Geometry string `json:"geometry,omitempty"`
// Steps are the stops in visiting order.
Steps []*RouteStep `json:"steps"`
}
VehicleRoute is the itinerary assigned to one vehicle.
type Waypoint ¶
type Waypoint struct {
// Name is the street the coordinate snapped to, if known.
Name string `json:"name"`
// Location is the snapped position.
Location Point `json:"location"`
// Distance is the metres between the input coordinate and Location.
Distance float64 `json:"distance"`
// Hint is an opaque token that can speed up subsequent requests.
Hint string `json:"hint,omitempty"`
// Nodes are the OSM node IDs of the snapped segment, when the engine
// returns them.
Nodes []int64 `json:"nodes,omitempty"`
}
Waypoint is an input coordinate snapped to the road network.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
geocode
command
Command geocode searches for an address and prints the matches.
|
Command geocode searches for an address and prints the matches. |
|
matching
command
Command matching snaps a noisy GPS trace onto the road network.
|
Command matching snaps a noisy GPS trace onto the road network. |
|
matrix
command
Command matrix computes travel times from a depot to several stops.
|
Command matrix computes travel times from a depot to several stops. |
|
nearest
command
Command nearest finds the road segment closest to a coordinate.
|
Command nearest finds the road segment closest to a coordinate. |
|
optimization
command
Command optimization assigns deliveries to a small fleet and prints the resulting routes.
|
Command optimization assigns deliveries to a small fleet and prints the resulting routes. |
|
route
command
Command route computes a route between two points and prints its distance.
|
Command route computes a route between two points and prints its distance. |
|
trip
command
Command trip finds the fastest order to visit a set of points.
|
Command trip finds the fastest order to visit a set of points. |