imroc / req

Simple Go HTTP client with Black Magic
https://req.cool
MIT License
4.12k stars 334 forks source link

add get/set context data in request #358

Closed RonaldinhoL closed 1 month ago

RonaldinhoL commented 1 month ago

add method for keep data during different callback and different retry round

imroc commented 1 month ago

You can use the go std context.Context to store your key/value pair context data, there is no need to add other functions and fields.

For example:

package main

import (
    "context"
    "fmt"

    "github.com/imroc/req/v3"
)

func printContextValue(hookName string, req *req.Request) {
    val, ok := req.Context().Value("test1").(string)
    if !ok {
        panic("no value found")
    }
    fmt.Println(hookName, "found test1: ", val)
}

func main() {
    client := req.C().
        SetCommonRetryCount(3).
        SetCommonRetryHook(func(resp *req.Response, err error) {
            req := resp.Request
            printContextValue("retry hook", req)
        }).
        SetCommonRetryCondition(func(resp *req.Response, err error) bool {
            return true
        }).
        OnBeforeRequest(func(client *req.Client, req *req.Request) error {
            printContextValue("request middleware", req)
            return nil
        })

    ctx := context.Background()
    ctx = context.WithValue(ctx, "test1", "data1")
    client.R().SetContext(ctx).MustGet("https://httpbin.org/get")
}
RonaldinhoL commented 1 month ago

this is not really convenient tho, i have common retry hooks but i need to add ctx value explicitly for every requests, which may only be used during retry and has nothing to do with current request

imroc commented 1 month ago

You're right, I can add this to Request (use context.Context to store data, no extra field):

func (r *Request) SetContextData(key, val any) *Request {
    r.ctx = context.WithValue(r.Context(), key, val)
    return r
}

func (r *Request) GetContextData(key any) any {
    return r.Context().Value(key)
}

Then it will be more convenient.

RonaldinhoL commented 1 month ago

could it be modified in this way ? SetContextData same key and diffrent value

imroc commented 1 month ago

could it be modified in this way ? SetContextData same key and diffrent value

Yes,new value will override the old value.

e.g.

package main

import (
    "fmt"

    "github.com/imroc/req/v3"
)

func main() {
    client := req.C().
        SetCommonRetryCount(3).
        SetCommonRetryHook(func(resp *req.Response, err error) {
            req := resp.Request
            if req.RetryAttempt > 0 { // set data on retry
                req.SetContextData("test1", fmt.Sprintf("data-%d", req.RetryAttempt))
            }
        }).
        SetCommonRetryCondition(func(resp *req.Response, err error) bool {
            return true
        }).
        OnBeforeRequest(func(client *req.Client, req *req.Request) error {
            fmt.Println("get data in middleware", req.GetContextData("test1"))
            return nil
        })

    client.R().MustGet("https://httpbin.org/get")
}

Output:

get data in middleware <nil>
get data in middleware data-1
get data in middleware data-2
get data in middleware data-3
imroc commented 1 month ago

Now you can upgrade to the latest release.

RonaldinhoL commented 1 month ago

cool great