package nominatim import ( "encoding/json" "fmt" "io" "net/http" "strconv" ) type Nominatim struct { siteName string } func New(siteName string) (*Nominatim, error) { if siteName == "" { return nil, fmt.Errorf("`siteName` must be defined.") } return &Nominatim{ siteName: siteName, }, nil } func (n *Nominatim) Search(q string) (*SearchResults, error) { url := fmt.Sprintf("https://nominatim.openstreetmap.org/search?q=%s&format=jsonv2", q) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } req.Header.Set("User-Agent", n.siteName) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%s", resp.Status) } body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } result := SearchResults{} err = json.Unmarshal(body, &result) if err != nil { return nil, err } return &result, nil } type LookupResult struct { Coordinates Location string `json:"location"` } func (n *Nominatim) Lookup(q string) (*LookupResult, error) { r, err := n.Search(q) if err != nil { return nil, err } if len(*r) == 0 { return nil, fmt.Errorf("no result") } firstResult := (*r)[0] lon, err := strconv.ParseFloat(*firstResult.Longitude, 64) if err != nil { return nil, err } lat, err := strconv.ParseFloat(*firstResult.Latitude, 64) if err != nil { return nil, err } return &LookupResult{ Location: *firstResult.Name, Coordinates: Coordinates{ Latitude: lat, Longitude: lon, }, }, nil }