github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2015/go-for-java-programmers/frontend.go (about) 1 // +build OMIT 2 3 // The server program issues Google search requests. It serves on port 8080. 4 // 5 // The /search endpoint accepts these query params: 6 // q=the Google search query 7 // 8 // For example, http://localhost:8080/search?q=golang serves the first 9 // few Google search results for "golang". 10 package main 11 12 import ( 13 "encoding/json" 14 "fmt" 15 "html/template" 16 "log" 17 "net/http" 18 "net/url" 19 "time" 20 ) 21 22 func main() { 23 http.HandleFunc("/search", handleSearch) // HL 24 fmt.Println("serving on http://localhost:8080/search") 25 log.Fatal(http.ListenAndServe("localhost:8080", nil)) 26 } 27 28 // handleSearch handles URLs like "/search?q=golang" by running a 29 // Google search for "golang" and writing the results as HTML to w. 30 func handleSearch(w http.ResponseWriter, req *http.Request) { 31 log.Println("serving", req.URL) 32 33 // Check the search query. 34 query := req.FormValue("q") // HL 35 if query == "" { 36 http.Error(w, `missing "q" URL parameter`, http.StatusBadRequest) 37 return 38 } 39 // ENDQUERY OMIT 40 41 // Run the Google search. 42 start := time.Now() 43 results, err := Search(query) // HL 44 elapsed := time.Since(start) 45 if err != nil { 46 http.Error(w, err.Error(), http.StatusInternalServerError) 47 return 48 } 49 // ENDSEARCH OMIT 50 51 // Render the results. 52 type templateData struct { 53 Results []Result 54 Elapsed time.Duration 55 } 56 if err := resultsTemplate.Execute(w, templateData{ // HL 57 Results: results, 58 Elapsed: elapsed, 59 }); err != nil { 60 log.Print(err) 61 return 62 } 63 // ENDRENDER OMIT 64 } 65 66 // A Result contains the title and URL of a search result. 67 type Result struct { // HL 68 Title, URL string // HL 69 } // HL 70 71 var resultsTemplate = template.Must(template.New("results").Parse(` 72 <html> 73 <head/> 74 <body> 75 <ol> 76 {{range .Results}} 77 <li>{{.Title}} - <a href="{{.URL}}">{{.URL}}</a></li> 78 {{end}} 79 </ol> 80 <p>{{len .Results}} results in {{.Elapsed}}</p> 81 </body> 82 </html> 83 `)) 84 85 // Search sends query to Google search and returns the results. 86 func Search(query string) ([]Result, error) { 87 // Prepare the Google Search API request. 88 u, err := url.Parse("https://ajax.googleapis.com/ajax/services/search/web?v=1.0") 89 if err != nil { 90 return nil, err 91 } 92 q := u.Query() 93 q.Set("q", query) // HL 94 u.RawQuery = q.Encode() 95 96 // Issue the HTTP request and handle the response. 97 resp, err := http.Get(u.String()) // HL 98 if err != nil { 99 return nil, err 100 } 101 defer resp.Body.Close() // HL 102 103 // Parse the JSON search result. 104 // https://developers.google.com/web-search/docs/#fonje 105 var jsonResponse struct { 106 ResponseData struct { 107 Results []struct { 108 TitleNoFormatting, URL string 109 } 110 } 111 } 112 if err := json.NewDecoder(resp.Body).Decode(&jsonResponse); err != nil { // HL 113 return nil, err 114 } 115 116 // Extract the Results from jsonResponse and return them. 117 var results []Result 118 for _, r := range jsonResponse.ResponseData.Results { // HL 119 results = append(results, Result{Title: r.TitleNoFormatting, URL: r.URL}) 120 } 121 return results, nil 122 }