gmaps.go
1 // SPDX-FileCopyrightText: Amolith <amolith@secluded.site> 2 // 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 5 package gmaps 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "strings" 13 ) 14 15 type GMapsResp struct { 16 Places []Place `json:"places"` 17 } 18 19 type Place struct { 20 FormattedAddress string `json:"formattedAddress"` 21 PlusCode PlusCode `json:"plusCode"` 22 DisplayName DisplayName `json:"displayName"` 23 Location Location `json:"location"` 24 } 25 26 type PlusCode struct { 27 GlobalCode string `json:"globalCode"` 28 CompoundCode string `json:"compoundCode"` 29 } 30 31 type Location struct { 32 Latitude float64 `json:"latitude"` 33 Longitude float64 `json:"longitude"` 34 } 35 36 type DisplayName struct { 37 Text string `json:"text"` 38 LanguageCode string `json:"languageCode"` 39 } 40 41 // Search queries the Google Maps API using the Text Search (New) endpoint 42 func Search(query, gMapsKey string) ([]Place, error) { 43 reqBody := map[string]string{ 44 "textQuery": query, 45 "languageCode": "en", 46 } 47 48 jsonBody, err := json.Marshal(reqBody) 49 if err != nil { 50 return nil, fmt.Errorf("failed to marshal request body: %w", err) 51 } 52 53 client := http.Client{} 54 req, err := http.NewRequest("POST", "https://places.googleapis.com/v1/places:searchText", strings.NewReader(string(jsonBody))) 55 if err != nil { 56 return nil, fmt.Errorf("failed to create HTTP request: %w", err) 57 } 58 59 req.Header = http.Header{} 60 req.Header.Add("Content-Type", "application/json") 61 req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0") 62 req.Header.Add("X-Goog-Api-Key", gMapsKey) 63 req.Header.Add("X-Goog-FieldMask", "places.formattedAddress,places.displayName,places.plusCode,places.location") 64 65 res, err := client.Do(req) 66 if err != nil { 67 return nil, fmt.Errorf("failed to execute HTTP request: %w", err) 68 } 69 70 body, err := io.ReadAll(res.Body) 71 if err != nil { 72 return nil, fmt.Errorf("failed to read response body: %w", err) 73 } 74 if err := res.Body.Close(); err != nil { 75 return nil, fmt.Errorf("failed to close response body: %w", err) 76 } 77 78 var gMapsResp GMapsResp 79 err = json.Unmarshal(body, &gMapsResp) 80 if err != nil { 81 return nil, fmt.Errorf("failed to unmarshal response body: %w", err) 82 } 83 84 return gMapsResp.Places, nil 85 }