smapp-sdk-go
is a golang sdk for using different Smapp services.
List of supported services are:
- Reverse Geocode
- Search
- Area Gateways
- ETA
- Matrix
- Routing
First set up your device to be able to use private golang packages from github.com/snapp-incubator
.
Then add this dependency in the format below to go.mod
file..
module YOUR_MODULE
go 1.17
require (
...
github.com/snapp-incubator/smapp-sdk-go v0.9.2
...
)
replace github.com/snapp-incubator/smapp-sdk-go => github.com/snapp-incubator/smapp-sdk-go.git v0.9.2
you can download the library with go mod download
command.
Note: Versions before
v0.9.1
will be deprecated soon.
for using Smapp SDK, you should instantiate a config first. a config object consists of common properties needed for using in different services.
configs can be instantiated with code or with environment variables.
import package github.com/snapp-incubator/smapp-sdk-go/config
for using it.
List of environment variables are:
SMAPP_API_KEY
: specifies api key for using smapp services. this environment variable isrequired
.SMAPP_API_KEY_SOURCE
: specifies the source of api key in a request. valid values areheader
andquery
. default value isheader
.SMAPP_API_KEY_NAME
: specifies the name of api key parameter (header name of query param name) in a request. default value isX-Smapp-Key
.SMAPP_API_REGION
: the region of smapp api should be specified here. valid values areteh-1
andteh-2
. default value isteh-1
SMAPP_API_BASE_URL
: is the base url of smapp services (API Gateway). default value ishttp://smapp-api.apps.inter-dc.okd4.teh-1.snappcloud.io
a config from environment could be instantiated like code below:
config, err := config.ReadFromEnvironment()
if err != nil {
panic(err)
}
these are default values of each config field:
- Region:
teh-1
- APIKeySource:
header
- APIKeyName:
X-Smapp-Key
- APIBaseURL:
http://smapp-api.apps.inter-dc.okd4.teh-1.snappcloud.io
a config could be instantiated like code below:
config, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
You may want to override some fields of the config object. you can pass multiple options to constructors for overriding config object.
List of options are:
- WithRegion(region string) : sets a region for the config.
- WithAPIKey(apikey string) : sets the APIKey for the config. it is often used as an option
in
ReadFromEnvironment
. - WithAPIBaseURL(baseURL string) : sets a custom base URL for API Gateway of smapp services.
- WithAPIKeySource(source APIKeySource) : sets an APIKeySource for the config.
- WithAPIKeyName(name string) : sets an APIKeyName for the config
- WithPublicURL() : sets the APIBaseURL to public routes of smapp. Notice: make sure you set region before using
this option. if not set
teh-1
region would be used as default region. - WithInternalURL() : sets the APIBaseURL to internal routes of smapp. Notice: make sure you set region before
using this option. if not set
teh-1
region would be used as default region.
Example:
cfg, err := config.ReadFromEnvironment(
config.WithRegion("teh-2"),
config.WithAPIKey("example-api-key"),
config.WithPublicURL(),
)
cfg2, err := NewDefaultConfig("api-key",
config.WithRegion("teh-2"),
config.WithAPIKeyName("X-Smapp-New-Key"),
config.WithPublicURL(),
)
After creating a config object, you can construct a reverse geo-code client for your services.
The constructor of Reverse Geocode receives a config, version, timeout and multiple optional options.
some constructor options are:
- WithURL(url string): could be used to override url of the service.
- WithTransport(transport *http.Transport): could be used to set a new
http.Transport
for http client. - WithRequestOpenTelemetryTracing(tracerName string): could be used for activating opentelemetry tracing on client. for more info see Here
Example:
package main
import (
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/reverse"
"time"
)
func main() {
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
reverseClient, err := reverse.NewReverseClient(cfg, reverse.V1, time.Second,
reverse.WithURL("https://new-url.com"), // This is optional
)
if err != nil {
panic(err)
}
displayName, err := reverseClient.GetDisplayName(35.0123, 53.12312, reverse.NewDefaultCallOptions())
if err != nil {
panic(err)
}
fmt.Println(displayName)
}
List of operations on a reverse geocode client are:
GetComponents(lat, lon float64, options CallOptions) ([]Component, error)
: receiveslat
,lon
andCallOptions
and returns components of address of location given.GetComponentsWithContext(ctx context.Context, lat, lon float64, options CallOptions) ([]Component, error)
: same asGetComponents
but you can pass your own context for more control if needed.GetDisplayName(lat, lon float64, options CallOptions) (string, error)
: receiveslat
,lon
andCallOptions
and returns a string as address of given location.GetDisplayNameWithContext(ctx context.Context, lat, lon float64, options CallOptions) (string, error)
: same asGetDisplayName
but you can pass your own context for more control if needed.GetFrequent(lat, lon float64, options CallOptions) (FrequentAddress, error)
: receiveslat
,lon
as a location and CallOptions and returns FrequentAddress for the given location.GetFrequentWithContext(ctx context.Context, lat, lon float64, options CallOptions) (FrequentAddress, error)
: same asGetFrequent
but you can pass your own context for more control if needed.GetBatch(request BatchReverseRequest) ([]Result, error)
receives a slice of Request s and returns Component s of address of location given. Does not support type 'frequent' in requests and Does not support type Display option as TrueGetBatchWithContext(ctx context.Context, request BatchReverseRequest) ([]Result, error)
same asGetBatch
but you can pass your own context for more control if needed.GetBatchDisplayName(request BatchReverseRequest) ([]Result, error)
receives a slice of Request s and returns Component s of address of location given, with only the DisplayName Only works when Display is trueGetBatchDisplayNameWithContext(ctx context.Context, request BatchReverseRequest) ([]Result, error)
same asGetBatchDisplayName
but you can pass your own context for more control if needed.
CallOptions
is a struct that defines the behaviour of the operation. you can create a new CallOptions
with reverse.NewDefaultCallOptions()
function. you can customize the behaviour with passing multiple call options to the constructor.
list of call options for reverse-geocode service are:
- WithZoomLevel(zoomLevel int): sets the zoom level for the request. default value is
16
- WithEnglishLanguage(): sets the language for response to English. default is
fa
(Farsi) - WithFarsiLanguage(): sets the language for response to Farsi.
- WithArabicLanguage(): sets the language for response to Arabic.
- WithPassengerResponseType(): sets the response type suitable for passengers.
- WithDriverResponseType(): sets the response type suitable for drivers.
- WithVerboseResponseType(): sets the response type to a verbose response.
- WithBikerResponseType(): sets the response type suitable for bikers
- WithOriginResponseType(): sets the response type for origin points.
- WithDestinationResponseType(): sets the response type for destination points.
- WithIraqResponseType(): sets the response type suitable for iraq country. it should be used just for Baly product.
- WithHeaders(headers map[string]string): sets custom headers for request.
This example will set zoom level of 17 with English response:
displayName, err := reverseClient.GetDisplayName(35.0123, 53.12312, reverse.NewDefaultCallOptions(
reverse.WithZoomLevel(17),
reverse.WithEnglishLanguage(),
))
if err != nil {
panic(err)
}
After creating a config object, you can construct a search client for your services.
The constructor of Search receives a config, version, timeout and multiple optional options.
some constructor options are:
- WithURL(url string): could be used to override url of the service.
- WithTransport(transport *http.Transport): could be used to set a new
http.Transport
for http client. - WithRequestOpenTelemetryTracing(tracerName string): could be used for activating opentelemetry tracing on client. for more info see Here
Example:
package main
import (
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/search"
"time"
)
func main() {
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
searchClient, err := search.NewSearchClient(cfg, search.V1, time.Second,
search.WithURL("https://new-url.com"), // This is optional
)
if err != nil {
panic(err)
}
results, err := searchClient.AutoComplete("example", search.NewDefaultCallOptions(
search.WithCityId(1000),
search.WithLocation(35.012, 53.1253),
))
if err != nil {
panic(err)
}
fmt.Println(results)
}
List of operations on a search client are:
GetCities(options CallOptions) ([]City, error)
: it receives call options and returns list of popular cities.GetCitiesWithContext(ctx context.Context, options CallOptions) ([]City, error)
: same asGetCities
but you can pass your context for more control.SearchCity(input string, options CallOptions) ([]City, error)
: receives an input string for search and callOptions and returns list of cities according to input string.SearchCityWithContext(ctx context.Context, input string, options CallOptions) ([]City, error)
: same asSearchCity
but you can pass your context for more control.AutoComplete(input string, options CallOptions) ([]Result, error)
: receives an input string and call options and returns all possible results according to input string.AutoCompleteWithContext(ctx context.Context, input string, options CallOptions) ([]Result, error)
: same asAutoComplete
but you can pass your context for more control.Details(placeId string, options CallOptions) (Detail, error)
: receives aplaceId
string and call options and returns details on that place id.DetailsWithContext(ctx context.Context, placeId string, options CallOptions) (Detail, error)
: same asDetails
but you can pass your context for more control.
CallOptions
is a struct that defines the behaviour of the operation. you can create a new CallOptions
with search.NewDefaultCallOptions()
function. you can customize the behaviour with passing multiple call options to the constructor.
list of call options for search service are:
- WithLocation(lat, lon float): The geographic point that search would be around it. May be user current location or center of the city that you want search in it. If location is empty, search boundary is whole of the country.
- WithUserLocation(lat, lon float): The current location of user. If you set location as center of a city, then you must fill this parameter with current location of user.
- WithEnglishLanguage(): sets the language for response to English. default is
fa
(Farsi) - WithFarsiLanguage(): sets the language for response to Farsi. default is
fa
(Farsi) - WithOriginRequestContext(): sets the context of current request to
origin
. - WithFavouriteRequestContext(): sets the context of current request to
favouritre
. - WithFirstDestinationRequestContext(): sets the context of current request to
destination1
. - WithSecondDestinationRequestContext(): sets the context of current request to
destination2
. - WithCityId(cityId int): sets the city id for better results in search.
- WithHeaders(headers map[string]string): sets custom headers for request.
This example will search for places like Azadi
with city id of 1000 (Tehran) and around the given location:
results, err := searchClient.AutoComplete("Azadi", search.NewDefaultCallOptions(
search.WithCityId(1000),
search.WithLocation(35.012, 53.1253),
))
if err != nil {
panic(err)
}
After creating a config object, you can construct an area-gateways client for your services.
The constructor of area-gateways receives a config, version, timeout and multiple optional options.
some constructor options are:
- WithURL(url string): could be used to override url of the service.
- WithTransport(transport *http.Transport): could be used to set a new
http.Transport
for http client. - WithRequestOpenTelemetryTracing(tracerName string): could be used for activating opentelemetry tracing on client. for more info see Here
Example:
package main
import (
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/area-gateways"
"time"
)
func main() {
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
areaGatewaysClient, err := area_gateways.NewAreaGatewaysClient(cfg, area_gateways.V1, time.Second)
if err != nil {
panic(err)
}
area, err := areaGatewaysClient.GetGateways(35.709374285391284, 51.40994310379028, area_gateways.NewDefaultCallOptions())
if err != nil {
panic(err)
}
fmt.Println(area)
}
List of operations on a area-gateways client are:
GetGateways(lat, lon float64, options CallOptions) (Area, error)
: it receiveslat
,lon
as a location and CallOptions and returns a polygon and its Gateways. It will return an Empty area if no area is found with given lat and lon.GetGatewaysWithContext(ctx context.Context, lat, lon float64, options CallOptions) (Area, error)
: same asGetGateways
but you can pass your context for more control.
CallOptions
is a struct that defines the behaviour of the operation. you can create a new CallOptions
with area_gateways.NewDefaultCallOptions()
function. you can customize the behaviour with passing multiple call options to the constructor.
list of call options for area-gateways service are:
- WithEnglishLanguage(): sets the language for response to English. default is
fa
(Farsi) - WithFarsiLanguage(): sets the language for response to Farsi. default is
fa
(Farsi) - WithHeaders(headers map[string]string): sets custom headers for request.
This example will get gateways with farsi language with the given location:
area, err := areaGatewaysClient.GetGateways(35.709374285391284, 51.40994310379028, area_gateways.NewDefaultCallOptions(
area_gateways.WithFarsiLanguage()
))
if err != nil {
panic(err)
}
After creating a config object, you can construct an ETA client for your services.
The constructor of ETA client receives a config, version, timeout and multiple optional options.
some constructor options are:
- WithURL(url string): could be used to override url of the service.
- WithTransport(transport *http.Transport): could be used to set a new
http.Transport
for http client. - WithRequestOpenTelemetryTracing(tracerName string): could be used for activating opentelemetry tracing on client. for more info see Here
Example:
package main
import (
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/eta"
"time"
)
func main() {
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
client, err := eta.NewETAClient(cfg, eta.V1, time.Second*10)
if err != nil {
panic(err)
}
results, err := client.GetETA([]eta.Point{
{
Lat: 35.77330981921435,
Lon: 51.41834378242493,
},
{
Lat: 35.739136559226864,
Lon: 51.510804891586304,
},
}, eta.NewDefaultCallOptions(
eta.WithHeaders(map[string]string{
"foo": "bar",
}),
eta.WithNoTraffic(),
WithEngine(EtaEngineV2),
),
)
if err != nil {
panic(err)
}
fmt.Println(results)
}
List of operations on a eta client are:
GetETA(points []Point, options CallOptions) (ETA, error)
: It will receive a list of point with minimum length of 2 and returns ETA. Will return error if less than 2 points are passed.GetETAWithContext(ctx context.Context, points []Point, options CallOptions) (ETA, error)
: same asGetETA
but you can pass your context for more control.
CallOptions
is a struct that defines the behaviour of the operation. you can create a new CallOptions
with eta.NewDefaultCallOptions()
function. you can customize the behaviour with passing multiple call options to the constructor.
list of call options for eta service are:
- WithNoTraffic(): sets
no_traffic
query param ro true. with this option eta requests does not involve traffic data in response - WithDepartureDateTime(dateTime string): sets the departure date time of the eta request. (format of date time
should be like
2006-01-02T15:04:05Z07:00
according to RFC3309) - WithHeaders(headers map[string]string): sets custom headers for request.
This example will get eta between the given locations:
results, err := client.GetETA([]eta.Point{
{
Lat: 35.77330981921435,
Lon: 51.41834378242493,
},
{
Lat: 35.739136559226864,
Lon: 51.510804891586304,
},
}, eta.NewDefaultCallOptions(
eta.WithNoTraffic(),
),
)
if err != nil {
panic(err)
}
After creating a config object, you can construct an Matrix client for your services.
The constructor of Matrix client receives a config, version, timeout and multiple optional options.
some constructor options are:
- WithURL(url string): could be used to override url of the service.
- WithTransport(transport *http.Transport): could be used to set a new
http.Transport
for http client. - WithRequestOpenTelemetryTracing(tracerName string): could be used for activating opentelemetry tracing on client. for more info see Here
Example:
package main
import (
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/matrix"
"time"
)
func main() {
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
client, err := matrix.NewMatrixClient(cfg, matrix.V1, time.Second*10)
if err != nil {
panic(err)
}
result, err := client.GetMatrix([]matrix.Point{
{
Lat: 35.7733304928583,
Lon: 51.418322660028934,
},
{
Lat: 35.72895575080859,
Lon: 51.37228488922119,
},
}, []matrix.Point{
{
Lat: 35.70033104179786,
Lon: 51.351492404937744,
},
{
Lat: 35.73933685292328,
Lon: 51.50890588760376,
},
}, matrix.NewDefaultCallOptions(
// if you want response with no traffic involved
matrix.WithNoTraffic(),
// if you want response with traffic involved
// matrix.WithTraffic(),
matrix.WithEngine(MatrixEngineV1),
matrix.WithHeaders(map[string]string{
"foo": "bar",
}),
))
if err != nil {
panic(err)
}
fmt.Println(result)
}
List of operations on a matrix client are:
GetMatrix(sources []Point, targets []Point, options CallOptions) (Output, error)
: It will receive a list of points as sources and a list of points as targets and returns a matrix of eta predictions from all sources to all targets. Will return error if sources or targets are empty.GetMatrixWithContext(ctx context.Context, sources []Point, targets []Point, options CallOptions) (Output, error)
: same asGetMatrix
but you can pass your context for more control.
CallOptions
is a struct that defines the behaviour of the operation. you can create a new CallOptions
with matrix.NewDefaultCallOptions()
function. you can customize the behaviour with passing multiple call options to the constructor.
list of call options for matrix service are:
-
WithNoTraffic(): sets
no_traffic
query param ro true. with this option eta requests does not involve traffic data in response -
WithEngine(MatrixEngine): sets the engine to be used in calculating the eta matrix.
-
WithHeaders(headers map[string]string): sets custom headers for request.
There is a mock client for each service for usage of mocking. mock package is used for this purpose.
an Example for mocking search client is:
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
// Assert that Bar() is invoked.
defer ctrl.Finish()
mockSearch := search.NewMockSearchClient(ctrl)
}
you can use mockSearch
to mock results of function calls of the client. for more information,
see here
WithRequestOpenTelemetryTracing
could be used to enable opentelemetry on the sdk.
you should use functions with WithContext
postfix of clients and pass a valid context of parent Span
s for proper tracing. it will act unexpected if configurations of opentelemetry are not valid.
Note make sure you have declared a global tracer (with
SetTracerProvider
function existing in opentelemtry library) and proper propagator (SetTextMapPropagator
function rxisting in opentelemetry library)
in this example we will configure a jaeger opentelemetry client with area-gateways
client.
package main
import (
"context"
"fmt"
"github.com/snapp-incubator/smapp-sdk-go/config"
"github.com/snapp-incubator/smapp-sdk-go/services/area-gateways"
jaeger_propagator "go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
traceSpan "go.opentelemetry.io/otel/trace"
"time"
)
func main() {
exp, err := jaeger.New(jaeger.WithAgentEndpoint(
jaeger.WithAgentHost("localhost"),
jaeger.WithAgentPort("6831"),
),
)
if err != nil {
panic(err)
}
tp := trace.NewTracerProvider(
trace.WithBatcher(exp),
trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(0.5))),
trace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("sample-tracer"),
),
),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(jaeger_propagator.Jaeger{})
cfg, err := config.NewDefaultConfig("api-key")
if err != nil {
panic(err)
}
areaGatewaysClient, err := area_gateways.NewAreaGatewaysClient(cfg, area_gateways.V1, time.Second,
area_gateways.WithRequestOpenTelemetryTracing("sample-tracer"),
)
if err != nil {
panic(err)
}
var sp traceSpan.Span
ctx, sp := otel.Tracer("test-test").Start(context.Background(), "start")
area, err := areaGatewaysClient.GetGatewaysWithContext(ctx, 35.709374285391284, 51.40994310379028, area_gateways.NewDefaultCallOptions())
if err != nil {
panic(err)
}
fmt.Println(area)
sp.End()
time.Sleep(10 * time.Second)
}