Files
services/geocoding/handler/handler.go
2021-05-05 10:37:23 +01:00

112 lines
2.7 KiB
Go

package handler
import (
"context"
"strings"
"github.com/micro/micro/v3/service/errors"
"github.com/micro/micro/v3/service/logger"
"googlemaps.github.io/maps"
pb "github.com/micro/services/geocoding/proto"
)
var (
ErrDownstream = errors.InternalServerError("MAP_ERROR", "Unable to connect to map provider")
ErrNoResults = errors.BadRequest("NO_RESULTS", "Unable to geocode address, no results found")
ErrMissingLatitude = errors.BadRequest("MISSING_LATITUDE", "Missing latitude")
ErrMissingLongitude = errors.BadRequest("MISSING_LONGITUDE", "Missing longitude")
)
type Geocoding struct {
Maps *maps.Client
}
func (g *Geocoding) Lookup(ctx context.Context, req *pb.LookupRequest, rsp *pb.LookupResponse) error {
// query google maps
results, err := g.Maps.Geocode(ctx, &maps.GeocodingRequest{Address: req.Address})
if err != nil {
logger.Errorf("Error geocoding: %v", err)
return ErrDownstream
}
if len(results) == 0 {
return ErrNoResults
}
rsp.Address = new(pb.Address)
rsp.Location = new(pb.Location)
// return the result
serializeResult(results[0], rsp.Address, rsp.Location)
return nil
}
// Reverse geocode an address
func (g *Geocoding) Reverse(ctx context.Context, req *pb.ReverseRequest, rsp *pb.ReverseResponse) error {
// validate the request
if req.Latitude == 0.0 {
return ErrMissingLatitude
}
if req.Longitude == 0.0 {
return ErrMissingLongitude
}
// query google maps
results, err := g.Maps.ReverseGeocode(ctx, &maps.GeocodingRequest{
LatLng: &maps.LatLng{Lat: req.Latitude, Lng: req.Longitude},
})
if err != nil {
logger.Errorf("Error geocoding: %v", err)
return ErrDownstream
}
if len(results) == 0 {
return ErrNoResults
}
rsp.Address = new(pb.Address)
rsp.Location = new(pb.Location)
// return the result
serializeResult(results[0], rsp.Address, rsp.Location)
return nil
}
func toString(a *pb.Address) string {
var comps []string
for _, c := range []string{a.LineOne, a.LineTwo, a.City, a.Postcode, a.Country} {
t := strings.TrimSpace(c)
if len(t) > 0 {
comps = append(comps, t)
}
}
return strings.Join(comps, ", ")
}
func serializeResult(r maps.GeocodingResult, a *pb.Address, l *pb.Location) {
var street, number string
for _, c := range r.AddressComponents {
for _, t := range c.Types {
switch t {
case "street_number":
number = c.LongName
case "route":
street = c.LongName
case "neighborhood":
a.LineTwo = c.LongName
case "country":
a.Country = c.LongName
case "postal_code":
a.Postcode = c.LongName
case "postal_town":
a.City = c.LongName
}
}
}
a.LineOne = strings.Join([]string{number, street}, " ")
l.Latitude = r.Geometry.Location.Lat
l.Longitude = r.Geometry.Location.Lng
}