Vá fazendo uma solicitação GET e construindo a Querystring


89

Eu sou muito novo em Go e não entendo muito bem tudo ainda. Em muitas das linguagens modernas Node.js, Angular, jQuery, PHP, você pode fazer uma solicitação GET com parâmetros de string de consulta adicionais.

Fazer isso no Go não é tão simples quanto parece, e eu realmente não consigo descobrir ainda. Eu realmente não quero ter que concatenar uma string para cada uma das solicitações que desejo fazer.

Aqui está o script de exemplo:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    client := &http.Client{}

    req, _ := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular", nil)
    req.Header.Add("Accept", "application/json")
    resp, err := client.Do(req)

    if err != nil {
        fmt.Println("Errored when sending request to the server")
        return
    }

    defer resp.Body.Close()
    resp_body, _ := ioutil.ReadAll(resp.Body)

    fmt.Println(resp.Status)
    fmt.Println(string(resp_body))
}

Neste exemplo, você pode ver que há um URL, que requer uma variável GET de api_key com sua chave de API como o valor. O problema é que isso se torna codificado na forma de:

req, _ := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular?api_key=mySuperAwesomeApiKey", nil)

Existe uma maneira de construir essa string de consulta dinamicamente ?? No momento, precisarei montar a URL antes desta etapa para obter uma resposta válida.


1
Então, o que há de errado em concatenar uma string?
Salvador Dali

4
Suponho que nada, mas não é realmente uma solução elegante, apenas pensei que havia uma maneira melhor de fazer as coisas em Go. Você vê as mudanças de ação, o método e então você tem que amarrar tudo junto.
Rudi Strydom

2
Você pode usar url.Valueso Encodemétodo de. Você também pode usar URL.Stringpara construir a URL inteira.
Dave C

Respostas:


213

Como um comentador mencionado, você pode obter Valuesde net/urlqual tem um Encodemétodo. Você poderia fazer algo assim ( req.URL.Query()retorna o existente url.Values)

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    req, err := http.NewRequest("GET", "http://api.themoviedb.org/3/tv/popular", nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }

    q := req.URL.Query()
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")
    req.URL.RawQuery = q.Encode()

    fmt.Println(req.URL.String())
    // Output:
    // http://api.themoviedb.org/3/tv/popular?another_thing=foo+%26+bar&api_key=key_from_environment_or_flag
}

http://play.golang.org/p/L5XCrw9VIG


1
Incrível, obrigado cara! Isso é exatamente o que eu estava procurando!
Rudi Strydom

Ótimo para testar também!
Kyle Chadha de

Alguma solução para fazer os parâmetros da string de consulta em sua ordem desejada? As chaves são classificadas no Encode()método.
artificerpi

1
@artificerpi se fosse crítico por algum motivo, você poderia reimplementar o que eles fazem dentro do método Encode golang.org/src/net/url/url.go?s=24222:24253#L845 Mas eu me perguntaria por que isso importa.
jcbwlkr

3
Você não precisa usar NewRequest se não estiver fazendo nada com ele. Você pode apenas usar em url.Parse("https://something.com/")vez disso ou até mesmo criar um objeto URL diretamente.
Richard

35

Use r.URL.Query()quando você anexar a uma consulta existente, se você estiver construindo um novo conjunto de parâmetros, use a url.Valuesestrutura assim

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/url"
    "os"
)

func main() {
    req, err := http.NewRequest("GET","http://api.themoviedb.org/3/tv/popular", nil)
    if err != nil {
        log.Print(err)
        os.Exit(1)
    }

    // if you appending to existing query this works fine 
    q := req.URL.Query()
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")

    // or you can create new url.Values struct and encode that like so
    q := url.Values{}
    q.Add("api_key", "key_from_environment_or_flag")
    q.Add("another_thing", "foo & bar")

    req.URL.RawQuery = q.Encode()

    fmt.Println(req.URL.String())
    // Output:
    // http://api.themoviedb.org/3/tv/popularanother_thing=foo+%26+bar&api_key=key_from_environment_or_flag
}

14

Usar NewRequestapenas para criar um URL é um exagero. Use o net/urlpacote:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    base, err := url.Parse("http://www.example.com")
    if err != nil {
        return
    }

    // Path params
    base.Path += "this will get automatically encoded"

    // Query params
    params := url.Values{}
    params.Add("q", "this will get encoded as well")
    base.RawQuery = params.Encode() 

    fmt.Printf("Encoded URL is %q\n", base.String())
}

Playground: https://play.golang.org/p/YCTvdluws-r


Concordo, ótima resposta!
pow-il

Essa realmente deveria ser a resposta aceita.
Paulo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.