// +build ignore,OMIT // The server program issues Google search requests. It serves on port 8080. // // The /search endpoint accepts these query params: // q=the Google search query // // For example, http://localhost:8080/search?q=golang serves the first // few Google search results for "golang". package main import ( "encoding/json" "fmt" "html/template" "log" "net/http" "net/url" "time" ) func main() { http.HandleFunc("/search", handleSearch) // HL fmt.Println("serving on http://localhost:8080/search") log.Fatal(http.ListenAndServe("localhost:8080", nil)) } // handleSearch handles URLs like "/search?q=golang" by running a // Google search for "golang" and writing the results as HTML to w. func handleSearch(w http.ResponseWriter, req *http.Request) { log.Println("serving", req.URL) // Check the search query. query := req.FormValue("q") // HL if query == "" { http.Error(w, `missing "q" URL parameter`, http.StatusBadRequest) return } // ENDQUERY OMIT // Run the Google search. start := time.Now() results, err := Search(query) // HL elapsed := time.Since(start) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // ENDSEARCH OMIT // Render the results. type templateData struct { Results []Result Elapsed time.Duration } if err := resultsTemplate.Execute(w, templateData{ // HL Results: results, Elapsed: elapsed, }); err != nil { log.Print(err) return } // ENDRENDER OMIT } // A Result contains the title and URL of a search result. type Result struct { // HL Title, URL string // HL } // HL var resultsTemplate = template.Must(template.New("results").Parse(`
{{len .Results}} results in {{.Elapsed}}
`)) // Search sends query to Google search and returns the results. func Search(query string) ([]Result, error) { // Prepare the Google Search API request. u, err := url.Parse("https://ajax.googleapis.com/ajax/services/search/web?v=1.0") if err != nil { return nil, err } q := u.Query() q.Set("q", query) // HL u.RawQuery = q.Encode() // Issue the HTTP request and handle the response. resp, err := http.Get(u.String()) // HL if err != nil { return nil, err } defer resp.Body.Close() // HL // Parse the JSON search result. // https://developers.google.com/web-search/docs/#fonje var jsonResponse struct { ResponseData struct { Results []struct { TitleNoFormatting, URL string } } } if err := json.NewDecoder(resp.Body).Decode(&jsonResponse); err != nil { // HL return nil, err } // Extract the Results from jsonResponse and return them. var results []Result for _, r := range jsonResponse.ResponseData.Results { // HL results = append(results, Result{Title: r.TitleNoFormatting, URL: r.URL}) } return results, nil }