Robert Strauch
Robert Strauch

Reputation: 12906

Adding a default HTTP header in Go

I'm taking my first steps in Go and would like to consume a REST API. The server requires each request to be authorized with a bearer token.

How can I add this header to the client so that every request uses this token?

import "net/http"

const accessToken = "MY_DEMO_TOKEN"

func main() {
    customHeader := http.Header{}
    customHeader.Add("Authorization: Bearer %s", accessToken)
    client := &http.Client{
        Timeout: time.Second*10,
    }
}

Upvotes: 9

Views: 13765

Answers (2)

Peter
Peter

Reputation: 31771

You can decorate the client's Transport. For instance:

package main

import "net/http"

func main() {
    client := http.DefaultClient

    rt := WithHeader(client.Transport)
    rt.Set("Authorization", "Bearer <token>")
    client.Transport = rt

    client.Get("http://example.com")
}

type withHeader struct {
    http.Header
    rt http.RoundTripper
}

func WithHeader(rt http.RoundTripper) withHeader {
    if rt == nil {
        rt = http.DefaultTransport
    }

    return withHeader{Header: make(http.Header), rt: rt}
}

func (h withHeader) RoundTrip(req *http.Request) (*http.Response, error) {
    if len(h.Header) == 0 {
        return h.rt.RoundTrip(req)
    }

    req = req.Clone(req.Context())
    for k, v := range h.Header {
        req.Header[k] = v
    }

    return h.rt.RoundTrip(req)
}

For the specific purpose of authorization tokens, you might be interested in the golang.org/x/oauth2 package, which does essentially the same, but also supports automatic token renewal:

package main

import (
    "context"

    "golang.org/x/oauth2"
)

func main() {
    ctx := context.Background()
    client := oauth2.NewClient(ctx, oauth2.StaticTokenSource(&oauth2.Token{
        AccessToken: "<your token>",
        TokenType:   "Bearer",
    }))

    client.Get("http://example.com")
}

Upvotes: 22

Maxim
Maxim

Reputation: 535

You can write a decorator around http.RoundTripper and pass it to the client. But practically I would end up with a helper that prepares request for each query as was suggested by Adrian.

package main

import (
    "fmt"
    "net/http"
    "time"
)

const accessToken = "MY_DEMO_TOKEN"

type MyRoundTripper struct {
    r http.RoundTripper
}

func (mrt MyRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
    r.Header.Add("Authorization", "Bearer: "+accessToken)
    return mrt.r.RoundTrip(r)
}

func main() {
    client := &http.Client{
        Timeout:   time.Second * 10,
        Transport: MyRoundTripper{r: http.DefaultTransport},
    }

    fmt.Println(client.Get("http://google.com/"))
}

Upvotes: 6

Related Questions