### Run the Example Source: https://github.com/imroc/req/blob/master/examples/find-popular-repo/README.md Execute the Go program to find the most popular repository. Ensure you have Go installed and the Req library is available. ```bash go run . ``` -------------------------------- ### Example Execution and Output Source: https://github.com/imroc/req/blob/master/examples/opentelemetry-jaeger-tracing/README.md Demonstrates running the example with a GitHub username and the expected output, including user and repository information. ```bash $ go run . Please give a github username: imroc The moust popular repo of roc (https://imroc.cc) is req, which have 2500 stars ``` -------------------------------- ### Simple GET Request with Explicit Client (Go) Source: https://github.com/imroc/req/blob/master/README.md Demonstrates how to create an explicit client instance and send a simple GET request. Recommended for production environments. ```go package main import ( "fmt" "github.com/imroc/req/v3" "log" ) func main() { client := req.C() // Use C() to create a client. resp, err := client.R(). // Use R() to create a request. Get("https://httpbin.org/uuid") if err != nil { log.Fatal(err) } fmt.Println(resp) } ``` -------------------------------- ### Example Output Prompt Source: https://github.com/imroc/req/blob/master/examples/opentelemetry-jaeger-tracing/README.md The application prompts for a GitHub username when executed. ```txt Please give a github username: ``` -------------------------------- ### Install req Go HTTP Client Source: https://github.com/imroc/req/blob/master/README.md Use this command to install the req library. Requires Go version 1.24+. ```sh go get github.com/imroc/req/v3 ``` -------------------------------- ### Build and Send HTTP Requests with req Source: https://context7.com/imroc/req/llms.txt Demonstrates building requests with path parameters, setting success and error result types for automatic unmarshalling, and handling different HTTP methods like GET and POST. Includes an example of the Do-style API for separating request construction from execution. ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type User struct { Login string `json:"login"` Name string `json:"name"` Blog string `json:"blog"` } type APIError struct { Message string `json:"message"` } func (e *APIError) Error() string { return "API error: " + e.Message } func main() { client := req.C().SetBaseURL("https://api.github.com") // --- GET with path param and automatic JSON unmarshal --- var user User var apiErr APIError resp, err := client.R(). SetPathParam("user", "imroc"). SetSuccessResult(&user). SetErrorResult(&apiErr). Get("/users/{user}") if err != nil { log.Fatal(err) } if resp.IsSuccessState() { fmt.Printf("%s (%s)\n", user.Name, user.Blog) } else if resp.IsErrorState() { fmt.Println("API error:", apiErr.Message) } // --- POST with JSON body --- type CreateIssue struct { Title string `json:"title"` Body string `json:"body"` } resp2, err := client.R(). SetBody(&CreateIssue{Title: "Bug report", Body: "Details here"}). Post("/repos/imroc/req/issues") if err != nil { log.Fatal(err) } fmt.Println("Created issue, status:", resp2.GetStatusCode()) // --- Do-style API --- var info map[string]any err = client.Get("/rate_limit").Do().Into(&info) if err != nil { log.Fatal(err) } fmt.Println("Rate limit info received") } ``` -------------------------------- ### Build GitHub SDK with Req (Style 1) Source: https://github.com/imroc/req/blob/master/README.md Example of building a GitHub SDK using Req. This style uses `SetSuccessResult` to directly set the target for unmarshalling and returns the error from the `Get` method. ```go import ( "context" "fmt" "github.com/imroc/req/v3" ) type ErrorMessage struct { Message string `json:"message"` } // Error implements go error interface. func (msg *ErrorMessage) Error() string { return fmt.Sprintf("API Error: %s", msg.Message) } type GithubClient struct { *req.Client } func NewGithubClient() *GithubClient { return &GithubClient{ Client: req.C(). SetBaseURL("https://api.github.com"). SetCommonErrorResult(&ErrorMessage{}). EnableDumpEachRequest(). OnAfterResponse(func(client *req.Client, resp *req.Response) error { if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error. return nil } if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok { resp.Err = errMsg // Convert api error into go error return nil } if !resp.IsSuccessState() { // Neither a success response nor a error response, record details to help troubleshooting resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump()) } return nil }), } } type UserProfile struct { Name string `json:"name"` Blog string `json:"blog"` } // GetUserProfile_Style1 returns the user profile for the specified user. // Github API doc: https://docs.github.com/en/rest/users/users#get-a-user func (c *GithubClient) GetUserProfile_Style1(ctx context.Context, username string) (user *UserProfile, err error) { _, err = c.R(). SetContext(ctx). SetPathParam("username", username). SetSuccessResult(&user). Get("/users/{username}") return } ``` -------------------------------- ### Client Creation and Basic Request Source: https://context7.com/imroc/req/llms.txt Demonstrates how to create a new client with custom configurations like base URL, user agent, timeout, common headers, and bearer token authentication. It also shows how to send a GET request and retrieve a JSON response. ```APIDOC ## Client Creation — `req.C()` / `req.NewClient()` `req.C()` constructs a new `*Client` with sensible defaults. Methods on the client are chainable. ### Description Creates a new `*Client` with default settings and allows for fluent configuration using chainable methods. ### Method `req.C()` ### Example Usage ```go package main import ( "fmt" "time" "github.com/imroc/req/v3" ) func main() { client := req.C(). SetBaseURL("https://api.github.com"). SetUserAgent("my-app/1.0"). SetTimeout(10 * time.Second). SetCommonHeader("Accept", "application/vnd.github.v3+json"). SetCommonBearerAuthToken("ghp_yourTokenHere"). EnableDebugLog() var result map[string]any resp, err := client.R(). SetSuccessResult(&result). Get("/repos/imroc/req") if err != nil { panic(err) } fmt.Println("Status:", resp.GetStatus()) fmt.Println("Full name:", result["full_name"]) } ``` ``` -------------------------------- ### Do API Style Example Source: https://github.com/imroc/req/blob/master/README.md Demonstrates how to make a POST request using the API style, setting the request body and unmarshalling the response. ```APIDOC ## Do API Style If you like, you can also use a Do API style like the following to make requests: ```go package main import ( "fmt" "github.com/imroc/req/v3" ) type APIResponse struct { Origin string `json:"origin"` Url string `json:"url"` } func main() { var resp APIResponse c := req.C().SetBaseURL("https://httpbin.org/post") err := c.Post(). SetBody("hello"). Do(). Into(&resp) if err != nil { panic(err) } fmt.Println("My IP is", resp.Origin) } ``` * The order of chain calls is more intuitive: first call Client to create a request with a specified Method, then use chain calls to set the request, then use `Do()` to fire the request, return Response, and finally call `Response.Into` to unmarshal response body into specified object. * `Response.Into` will return an error if an error occurs during sending the request or during unmarshalling. * The url of some APIs is fixed, and different types of requests are implemented by passing different bodies. In this scenario, `Client.SetBaseURL` can be used to set a unified url, and there is no need to set the url for each request when initiating a request. Of course, you can also call `Request.SetURL` to set it if you need it. ``` -------------------------------- ### Enable DevMode and Send GET Request (Go) Source: https://github.com/imroc/req/blob/master/README.md Enables development mode for detailed request logging and sends a GET request using global wrapper methods. Useful for quick testing and debugging. ```go package main import ( "github.com/imroc/req/v3" ) func main() { req.DevMode() // Treat the package name as a Client, enable development mode req.MustGet("https://httpbin.org/uuid") // Treat the package name as a Request, send GET request. req.EnableForceHTTP1() // Force using HTTP/1.1 req.MustGet("https://httpbin.org/uuid") } ``` -------------------------------- ### Build SDK With Req - Style 1 Source: https://github.com/imroc/req/blob/master/README.md Example of building a GitHub SDK using Req, demonstrating GetUserProfile_Style1 which uses chained method calls to configure and execute the request. ```APIDOC ## Build SDK With Req Here is an example of building GitHub's SDK with req, using two styles (`GetUserProfile_Style1`, `GetUserProfile_Style2`). ```go import ( "context" "fmt" "github.com/imroc/req/v3" ) type ErrorMessage struct { Message string `json:"message"` } // Error implements go error interface. func (msg *ErrorMessage) Error() string { return fmt.Sprintf("API Error: %s", msg.Message) } type GithubClient struct { *req.Client } func NewGithubClient() *GithubClient { return &GithubClient{ Client: req.C(). SetBaseURL("https://api.github.com"). SetCommonErrorResult(&ErrorMessage{}). EnableDumpEachRequest(). OnAfterResponse(func(client *req.Client, resp *req.Response) error { if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error. return nil } if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok { resp.Err = errMsg // Convert api error into go error return nil } if !resp.IsSuccessState() { // Neither a success response nor a error response, record details to help troubleshooting resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump()) } return nil }), } } type UserProfile struct { Name string `json:"name"` Blog string `json:"blog"` } // GetUserProfile_Style1 returns the user profile for the specified user. // Github API doc: https://docs.github.com/en/rest/users/users#get-a-user func (c *GithubClient) GetUserProfile_Style1(ctx context.Context, username string) (user *UserProfile, err error) { _, err = c.R(). SetContext(ctx). SetPathParam("username", username). SetSuccessResult(&user). Get("/users/{username}") return } ``` -------------------------------- ### Advanced GET Request with Client Configuration (Go) Source: https://github.com/imroc/req/blob/master/README.md Shows an advanced GET request with custom client settings like User-Agent and Timeout, and request settings like Headers, Success/Error Results, and Dump enabling. Includes detailed error handling and state checking. ```go package main import ( "fmt" "github.com/imroc/req/v3" "log" "time" ) type ErrorMessage struct { Message string `json:"message"` } type UserInfo struct { Name string `json:"name"` Blog string `json:"blog"` } func main() { client := req.C(). SetUserAgent("my-custom-client"). // Chainable client settings. SetTimeout(5 * time.Second) var userInfo UserInfo var errMsg ErrorMessage resp, err := client.R(). SetHeader("Accept", "application/vnd.github.v3+json"). // Chainable request settings. SetPathParam("username", "imroc"). // Replace path variable in url. SetSuccessResult(&userInfo). // Unmarshal response body into userInfo automatically if status code is between 200 and 299. SetErrorResult(&errMsg). // Unmarshal response body into errMsg automatically if status code >= 400. EnableDump(). // Enable dump at request level, only print dump content if there is an error or some unknown situation occurs to help troubleshoot. Get("https://api.github.com/users/{username}") if err != nil { // Error handling. log.Println("error:", err) log.Println("raw content:") log.Println(resp.Dump()) // Record raw content when error occurs. return } if resp.IsErrorState() { // Status code >= 400. fmt.Println(errMsg.Message) // Record error message returned. return } if resp.IsSuccessState() { // Status code is between 200 and 299. fmt.Printf("%s (%s)\n", userInfo.Name, userInfo.Blog) return } // Unknown status code. log.Println("unknown status", resp.Status) log.Println("raw content:") log.Println(resp.Dump()) // Record raw content when server returned unknown status code. } ``` -------------------------------- ### Build SDK With Req - Style 2 Source: https://github.com/imroc/req/blob/master/README.md Example of building a GitHub SDK using Req, demonstrating GetUserProfile_Style2 which uses a more direct method chaining for request execution and response handling. ```APIDOC // GetUserProfile_Style2 returns the user profile for the specified user. // Github API doc: https://docs.github.com/en/rest/users/users#get-a-user func (c *GithubClient) GetUserProfile_Style2(ctx context.Context, username string) (user *UserProfile, err error) { err = c.Get("/users/{username}"). SetPathParam("username", username). Do(ctx). Into(&user) return } ``` -------------------------------- ### Request Building and HTTP Methods Source: https://context7.com/imroc/req/llms.txt Illustrates how to build requests using `client.R()` and send them with various HTTP methods like GET, POST. It covers setting path parameters, handling JSON request bodies, and unmarshalling JSON responses, including error handling. ```APIDOC ## Request Building and HTTP Methods — `client.R()`, `.Get()`, `.Post()`, etc. `client.R()` creates a new `*Request`. Methods like `.Get(url)`, `.Post(url)`, etc., send the request. ### Description Builds and sends HTTP requests using various methods, supporting path parameters, request bodies, and response unmarshalling. ### Methods - `.Get(url)` - `.Post(url)` - `.Put(url)` - `.Patch(url)` - `.Delete(url)` - `.Head(url)` - `.Options(url)` ### Example Usage ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type User struct { Login string `json:"login"` Name string `json:"name"` Blog string `json:"blog"` } type APIError struct { Message string `json:"message"` } func (e *APIError) Error() string { return "API error: " + e.Message } func main() { client := req.C().SetBaseURL("https://api.github.com") // --- GET with path param and automatic JSON unmarshal --- var user User var apiErr APIError resp, err := client.R(). SetPathParam("user", "imroc"). SetSuccessResult(&user). SetErrorResult(&apiErr). Get("/users/{user}") if err != nil { log.Fatal(err) } if resp.IsSuccessState() { fmt.Printf("%s (%s)\n", user.Name, user.Blog) } else if resp.IsErrorState() { fmt.Println("API error:", apiErr.Message) } // --- POST with JSON body --- type CreateIssue struct { Title string `json:"title"` Body string `json:"body"` } resp2, err := client.R(). SetBody(&CreateIssue{Title: "Bug report", Body: "Details here"}). Post("/repos/imroc/req/issues") if err != nil { log.Fatal(err) } fmt.Println("Created issue, status:", resp2.GetStatusCode()) // --- Do-style API --- var info map[string]any err = client.Get("/rate_limit").Do().Into(&info) if err != nil { log.Fatal(err) } fmt.Println("Rate limit info received") } ``` ``` -------------------------------- ### Handling HTTP Responses with req Source: https://context7.com/imroc/req/llms.txt Demonstrates how to make a GET request and access various response details like status code, content type, and custom headers. It also shows how to set a success result type for automatic unmarshalling and how to manually unmarshal JSON or access raw bytes. ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type Repo struct { FullName string `json:"full_name"` Stars int `json:"stargazers_count"` Description string `json:"description"` } func main() { resp, err := req.C().R(). SetSuccessResult(&Repo{}). Get("https://api.github.com/repos/imroc/req") if err != nil { log.Fatal(err) } fmt.Println("Status Code:", resp.GetStatusCode()) // 200 fmt.Println("Status:", resp.GetStatus()) // "200 OK" fmt.Println("Content-Type:", resp.GetContentType()) // "application/json; charset=utf-8" fmt.Println("X-RateLimit:", resp.GetHeader("X-RateLimit-Remaining")) fmt.Println("Success?", resp.IsSuccessState()) // true fmt.Println("Total time:", resp.TotalTime()) if repo, ok := resp.SuccessResult().(*Repo); ok { fmt.Printf("%s (%d stars)\n", repo.FullName, repo.Stars) } // Manual unmarshal (alternative) var data map[string]any if err := resp.UnmarshalJson(&data); err != nil { log.Fatal(err) } // Into is a shorthand for Unmarshal (picks JSON vs XML by Content-Type) var repo2 Repo if err := resp.Into(&repo2); err != nil { log.Fatal(err) } // Raw bytes / string bodyBytes := resp.Bytes() // []byte bodyStr := resp.String() // string _ = bodyBytes _ = bodyStr } ``` -------------------------------- ### Advanced GET Request with Error Handling Source: https://github.com/imroc/req/blob/master/README.md Demonstrates setting up unified error handling for client requests, focusing on success scenarios and reducing duplicate code. Includes custom error types and response interceptors. ```go package main import ( "fmt" "github.com/imroc/req/v3" "log" "time" ) type ErrorMessage struct { Message string `json:"message"` } func (msg *ErrorMessage) Error() string { return fmt.Sprintf("API Error: %s", msg.Message) } type UserInfo struct { Name string `json:"name"` Blog string `json:"blog"` } var client = req.C(). SetUserAgent("my-custom-client"). // Chainable client settings. SetTimeout(5 * time.Second). EnableDumpEachRequest(). SetCommonErrorResult(&ErrorMessage{}). OnAfterResponse(func(client *req.Client, resp *req.Response) error { if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error. return nil } if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok { resp.Err = errMsg // Convert api error into go error return nil } if !resp.IsSuccessState() { // Neither a success response nor a error response, record details to help troubleshooting resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump()) } return nil }) func main() { var userInfo UserInfo resp, err := client.R(). SetHeader("Accept", "application/vnd.github.v3+json"). // Chainable request settings SetPathParam("username", "imroc"). SetSuccessResult(&userInfo). // Unmarshal response body into userInfo automatically if status code is between 200 and 299. Get("https://api.github.com/users/{username}") if err != nil { // Error handling. log.Println("error:", err) return } if resp.IsSuccessState() { // Status code is between 200 and 299. fmt.Printf("%s (%s)\n", userInfo.Name, userInfo.Blog) } } ``` -------------------------------- ### Using Global Wrapper Functions for HTTP Requests Source: https://context7.com/imroc/req/llms.txt Demonstrates one-liner requests using the package-level default client, enabling global dev mode, configuring the default client with base URL and headers, and replacing the default client. ```go package main import ( "fmt" "github.com/imroc/req/v3" ) func main() { // One-liner requests using the package-level default client fmt.Println(req.MustGet("https://httpbin.org/uuid")) // Global dev mode req.DevMode() req.MustGet("https://httpbin.org/get") // Configure the default client and use global helpers req.SetBaseURL("https://api.github.com"). SetCommonHeader("Accept", "application/vnd.github.v3+json"). SetTimeout(10e9) var user map[string]any req.SetSuccessResult(&user). SetPathParam("u", "imroc"). MustGet("/users/{u}") fmt.Println(user["name"]) // Replace default client entirely myClient := req.C().SetBaseURL("https://example.com").EnableDebugLog() req.SetDefaultClient(myClient) req.MustGet("/api/health") // uses myClient } ``` -------------------------------- ### Create and Configure a req Client Source: https://context7.com/imroc/req/llms.txt Instantiate a new client with custom settings like base URL, user agent, timeout, headers, and authentication. Enables debug logging for request/response details. Use for production applications to reuse a configured client. ```go package main import ( "fmt" "time" "github.com/imroc/req/v3" ) func main() { client := req.C(). SetBaseURL("https://api.github.com"). SetUserAgent("my-app/1.0"). SetTimeout(10 * time.Second). SetCommonHeader("Accept", "application/vnd.github.v3+json"). SetCommonBearerAuthToken("ghp_yourTokenHere"). EnableDebugLog() var result map[string]any resp, err := client.R(). SetSuccessResult(&result). Get("/repos/imroc/req") if err != nil { panic(err) } fmt.Println("Status:", resp.GetStatus()) fmt.Println("Full name:", result["full_name"]) } ``` -------------------------------- ### Set Request Headers, Query Params, and Path Params Source: https://context7.com/imroc/req/llms.txt Demonstrates setting common headers and query parameters at the client level, and specific path parameters, headers, and query parameters from a struct at the request level. Ensure path parameters are correctly formatted as {key} in the URL template. ```go package main import ( "fmt" "github.com/imroc/req/v3" ) type SearchFilter struct { Q string `url:"q"` Sort string `url:"sort"` PerPage int `url:"per_page"` } func main() { client := req.C(). SetBaseURL("https://api.github.com"). SetCommonHeader("Accept", "application/vnd.github.v3+json"). SetCommonQueryParam("api_version", "2022-11-28") var result map[string]any resp, err := client.R(). // Path parameter replaces {owner}/{repo} in URL SetPathParams(map[string]string{ "owner": "imroc", "repo": "req", }). // Additional headers for this request only SetHeaders(map[string]string{ "X-Request-ID": "abc-123", }). // Query params from a tagged struct SetQueryParamsFromStruct(SearchFilter{Q: "http", Sort: "stars", PerPage: 5}). SetSuccessResult(&result). Get("/repos/{owner}/{repo}/issues") if err != nil { panic(err) } fmt.Println(resp.GetStatus()) } ``` -------------------------------- ### Run Upload Server Source: https://github.com/imroc/req/blob/master/examples/upload/README.md Navigate to the uploadserver directory and run the server using 'go run .'. ```go cd uploadserver go run . ``` -------------------------------- ### Run Upload Client Source: https://github.com/imroc/req/blob/master/examples/upload/README.md Navigate to the uploadclient directory and run the client using 'go run .'. ```go cd uploadclient go run . ``` -------------------------------- ### Configure TLS and Proxy Settings Source: https://context7.com/imroc/req/llms.txt Customize TLS verification, client certificates, root CAs, and HTTP proxies. `EnableInsecureSkipVerify` should only be used for development or testing. Proxies can be set via URL or a custom function for dynamic routing. ```go package main import ( "crypto/tls" "fmt" "net/url" "github.com/imroc/req/v3" ) func main() { // Skip TLS verification (dev/test only) insecureClient := req.C().EnableInsecureSkipVerify() resp := insecureClient.R().MustGet("https://self-signed.example.com/api") fmt.Println(resp.GetStatus()) // Mutual TLS with client certificate mtlsClient := req.C(). SetCertFromFile("client.crt", "client.key"). SetRootCertsFromFile("ca.pem") resp, err := mtlsClient.R().Get("https://secure.example.com/api") fmt.Println(err, resp.GetStatus()) // HTTP proxy proxyClient := req.C().SetProxyURL("http://proxy.corp.internal:3128") resp = proxyClient.R().MustGet("https://httpbin.org/ip") fmt.Println(resp.GetStatus()) // Custom proxy function (e.g. per-request routing) dynamicProxyClient := req.C().SetProxy(func(r *req.RawRequest) (*url.URL, error) { if r.URL.Host == "sensitive.example.com" { return url.Parse("http://secure-proxy:8080") } return nil, nil // direct connection }) _ = dynamicProxyClient // Custom TLS config customTLSClient := req.C().SetTLSClientConfig(&tls.Config{ MinVersion: tls.VersionTLS12, }) _ = customTLSClient } ``` -------------------------------- ### Simple POST Request Source: https://github.com/imroc/req/blob/master/README.md Demonstrates a basic POST request with a JSON body and handling the response. Includes setting up a client and unmarshalling the success result. ```go package main import ( "fmt" "github.com/imroc/req/v3" "log" ) type Repo struct { Name string `json:"name"` Url string `json:"url"` } type Result struct { Data string `json:"data"` } func main() { client := req.C().DevMode() var result Result resp, err := client.R(). SetBody(&Repo{Name: "req", Url: "https://github.com/imroc/req"}). SetSuccessResult(&result). Post("https://httpbin.org/post") if err != nil { log.Fatal(err) } if !resp.IsSuccessState() { fmt.Println("bad response status:", resp.Status) return } fmt.Println("++++++++++++++++++++++++++++++++++++++++++++++++") fmt.Println("data:", result.Data) fmt.Println("++++++++++++++++++++++++++++++++++++++++++++++++") } ``` ```txt 2022/05/19 20:11:00.151171 DEBUG [req] HTTP/2 POST https://httpbin.org/post :authority: httpbin.org :method: POST :path: /post :scheme: https user-agent: req/v3 (https://github.com/imroc/req/v3) content-type: application/json; charset=utf-8 content-length: 55 accept-encoding: gzip {"name":"req","website":"https://github.com/imroc/req"} :status: 200 date: Thu, 19 May 2022 12:11:00 GMT content-type: application/json content-length: 651 server: gunicorn/19.9.0 access-control-allow-origin: * access-control-allow-credentials: true { "args": {}, "data": "{\"name\":\"req\",\"website\":\"https://github.com/imroc/req\"}", "files": {}, "form": {}, "headers": { "Accept-Encoding": "gzip", "Content-Length": "55", "Content-Type": "application/json; charset=utf-8", "Host": "httpbin.org", "User-Agent": "req/v3 (https://github.com/imroc/req/v3)", "X-Amzn-Trace-Id": "Root=1-628633d4-7559d633152b4307288ead2e" }, "json": { "name": "req", "website": "https://github.com/imroc/req" }, "origin": "103.7.29.30", "url": "https://httpbin.org/post" } ++++++++++++++++++++++++++++++++++++++++++++++++ data: {"name":"req","url":"https://github.com/imroc/req"} ++++++++++++++++++++++++++++++++++++++++++++++++ ``` -------------------------------- ### Build GitHub SDK with Req (Style 2) Source: https://github.com/imroc/req/blob/master/README.md An alternative style for building a GitHub SDK with Req. This approach uses `Do(ctx).Into(&user)` to execute the request and unmarshal the response. ```go import ( "context" "fmt" "github.com/imroc/req/v3" ) type ErrorMessage struct { Message string `json:"message"` } // Error implements go error interface. func (msg *ErrorMessage) Error() string { return fmt.Sprintf("API Error: %s", msg.Message) } type GithubClient struct { *req.Client } func NewGithubClient() *GithubClient { return &GithubClient{ Client: req.C(). SetBaseURL("https://api.github.com"). SetCommonErrorResult(&ErrorMessage{}). EnableDumpEachRequest(). OnAfterResponse(func(client *req.Client, resp *req.Response) error { if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error. return nil } if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok { resp.Err = errMsg // Convert api error into go error return nil } if !resp.IsSuccessState() { // Neither a success response nor a error response, record details to help troubleshooting resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump()) } return nil }), } } type UserProfile struct { Name string `json:"name"` Blog string `json:"blog"` } // GetUserProfile_Style2 returns the user profile for the specified user. // Github API doc: https://docs.github.com/en/rest/users/users#get-a-user func (c *GithubClient) GetUserProfile_Style2(ctx context.Context, username string) (user *UserProfile, err error) { err = c.Get("/users/{username}"). SetPathParam("username", username). Do(ctx). Into(&user) return } ``` -------------------------------- ### Download Files with Progress Callback Source: https://context7.com/imroc/req/llms.txt Downloads a file and saves it to disk or an io.Writer, with an optional progress callback. Sets a base directory for all relative output file paths. ```go package main import ( "fmt" "os" "time" "github.com/imroc/req/v3" ) func main() { client := req.C().SetOutputDirectory("/tmp/downloads") // Download to file (relative to output directory) resp, err := client.R(). SetOutputFile("go1.21.linux-amd64.tar.gz"). SetDownloadCallbackWithInterval(func(info req.DownloadInfo) { if info.Response.ContentLength > 0 { pct := float64(info.DownloadedSize) / float64(info.Response.ContentLength) * 100 fmt.Printf("\r%.1f%%", pct) } else { fmt.Printf("\r%d bytes", info.DownloadedSize) } }, 500*time.Millisecond). Get("https://go.dev/dl/go1.21.0.linux-amd64.tar.gz") fmt.Println() if err != nil { fmt.Fprintln(os.Stderr, err) return } fmt.Println("Downloaded:", resp.GetStatus()) // Download to writer (e.g. os.Stdout or in-memory buffer) resp, err = client.R(). SetOutput(os.Stdout). Get("https://httpbin.org/uuid") fmt.Println(err, resp.GetStatus()) } ``` -------------------------------- ### Request Headers, Query Params, and Path Params Source: https://context7.com/imroc/req/llms.txt Demonstrates how to set common request parameters like headers, query parameters, and path parameters. Path parameters are defined using `{key}` placeholders in the URL, while query parameters can be set using maps, structs, or raw query strings. Client-level settings apply to all requests, while request-level settings override or add to them. ```APIDOC ## Request Headers, Query Params, and Path Params Headers, query parameters, and URL path variables can be set at both the client level (applied to every request) and the request level (applied to one request). Path parameters use `{key}` placeholders in the URL template. Query parameters can be provided as maps, `url.Values`, raw query strings, or structs tagged with `url:""`. ```go package main import ( "fmt" "github.com/imroc/req/v3" ) type SearchFilter struct { Q string `url:"q"` Sort string `url:"sort"` PerPage int `url:"per_page"` } func main() { client := req.C(). SetBaseURL("https://api.github.com"). SetCommonHeader("Accept", "application/vnd.github.v3+json"). SetCommonQueryParam("api_version", "2022-11-28") var result map[string]any resp, err := client.R(). // Path parameter replaces {owner}/{repo} in URL SetPathParams(map[string]string{ "owner": "imroc", "repo": "req", }). // Additional headers for this request only SetHeaders(map[string]string{ "X-Request-ID": "abc-123", }). // Query params from a tagged struct SetQueryParamsFromStruct(SearchFilter{Q: "http", Sort: "stars", PerPage: 5}). SetSuccessResult(&result). Get("/repos/{owner}/{repo}/issues") if err != nil { panic(err) } fmt.Println(resp.GetStatus()) } ``` ``` -------------------------------- ### Middleware Source: https://context7.com/imroc/req/llms.txt Explains how to use `OnBeforeRequest` and `OnAfterResponse` middleware for request and response processing, such as authentication and error handling. ```APIDOC ## Middleware — `OnBeforeRequest` / `OnAfterResponse` Request middleware (`RequestMiddleware`) runs before a request is sent; response middleware (`ResponseMiddleware`) runs after a response is received. Multiple middlewares are stacked in order. They are the primary place for centralized authentication refresh, unified error conversion, logging, and metrics. ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type APIError struct { Code int `json:"code"` Message string `json:"message"` } func (e *APIError) Error() string { return fmt.Sprintf("API %d: %s", e.Code, e.Message) } func main() { client := req.C(). SetBaseURL("https://api.example.com"). SetCommonErrorResult(&APIError{}). // Request middleware: inject auth token OnBeforeRequest(func(c *req.Client, r *req.Request) error { r.SetBearerAuthToken("dynamic-token-here") return nil }). // Response middleware: convert API errors to Go errors OnAfterResponse(func(c *req.Client, resp *req.Response) error { if resp.Err != nil { return nil // underlying network/unmarshal error, skip } if apiErr, ok := resp.ErrorResult().(*APIError); ok { resp.Err = apiErr // expose as Go error return nil } if !resp.IsSuccessState() { resp.Err = fmt.Errorf("unexpected status %s:\n%s", resp.Status, resp.Dump()) } return nil }) var profile map[string]any _, err := client.R(). SetSuccessResult(&profile). Get("/users/me") if err != nil { log.Fatal(err) // APIError or network error } fmt.Println(profile) } ``` ``` -------------------------------- ### Implementing Request and Response Middleware Source: https://context7.com/imroc/req/llms.txt Shows how to use `OnBeforeRequest` to modify outgoing requests (e.g., adding auth tokens) and `OnAfterResponse` to process incoming responses. This is useful for centralized error handling, authentication, logging, and metrics. ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type APIError struct { Code int `json:"code"` Message string `json:"message"` } func (e *APIError) Error() string { return fmt.Sprintf("API %d: %s", e.Code, e.Message) } func main() { client := req.C(). SetBaseURL("https://api.example.com"). SetCommonErrorResult(&APIError{}). // Request middleware: inject auth token OnBeforeRequest(func(c *req.Client, r *req.Request) error { r.SetBearerAuthToken("dynamic-token-here") return nil }). // Response middleware: convert API errors to Go errors OnAfterResponse(func(c *req.Client, resp *req.Response) error { if resp.Err != nil { return nil // underlying network/unmarshal error, skip } if apiErr, ok := resp.ErrorResult().(*APIError); ok { resp.Err = apiErr // expose as Go error return nil } if !resp.IsSuccessState() { resp.Err = fmt.Errorf("unexpected status %s:\n%s", resp.Status, resp.Dump()) } return nil }) var profile map[string]any _, err := client.R(). SetSuccessResult(&profile). Get("/users/me") if err != nil { log.Fatal(err) // APIError or network error } fmt.Println(profile) } ``` -------------------------------- ### Response Handling Source: https://context7.com/imroc/req/llms.txt Demonstrates how to use the `Response` methods to check status, read bodies, and unmarshal data. It also shows how to access raw bytes and strings. ```APIDOC ## Response Handling — `Response` Methods `*Response` embeds `*http.Response` and adds helpers for state checks, body reading, and unmarshalling. `IsSuccessState()` returns true for 2xx, `IsErrorState()` for 4xx+. Body is automatically read into memory unless `DisableAutoReadResponse` is set. `ToBytes()` / `ToString()` lazily read the body; `Bytes()` / `String()` return already-read bytes. ```go package main import ( "fmt" "log" "github.com/imroc/req/v3" ) type Repo struct { FullName string `json:"full_name"` Stars int `json:"stargazers_count"` Description string `json:"description"` } func main() { resp, err := req.C().R(). SetSuccessResult(&Repo{}). Get("https://api.github.com/repos/imroc/req") if err != nil { log.Fatal(err) } fmt.Println("Status Code:", resp.GetStatusCode()) // 200 fmt.Println("Status:", resp.GetStatus()) // "200 OK" fmt.Println("Content-Type:", resp.GetContentType()) // "application/json; charset=utf-8" fmt.Println("X-RateLimit:", resp.GetHeader("X-RateLimit-Remaining")) fmt.Println("Success?", resp.IsSuccessState()) // true fmt.Println("Total time:", resp.TotalTime()) if repo, ok := resp.SuccessResult().(*Repo); ok { fmt.Printf("%s (%d stars)\n", repo.FullName, repo.Stars) } // Manual unmarshal (alternative) var data map[string]any if err := resp.UnmarshalJson(&data); err != nil { log.Fatal(err) } // Into is a shorthand for Unmarshal (picks JSON vs XML by Content-Type) var repo2 Repo if err := resp.Into(&repo2); err != nil { log.Fatal(err) } // Raw bytes / string bodyBytes := resp.Bytes() // []byte bodyStr := resp.String() // string _ = bodyBytes _ = bodyStr } ``` ``` -------------------------------- ### File Upload Source: https://context7.com/imroc/req/llms.txt Demonstrates various methods for uploading files, including simple uploads, uploads with progress callbacks, and uploading multiple files using FileUpload structs. ```APIDOC ## File Upload — `SetFile`, `SetFileUpload`, `SetUploadCallback` Files are attached as multipart form-data using `SetFile(paramName, filePath)` or the more flexible `SetFileUpload(FileUpload{…})`. Multiple files and form fields can be combined freely. Upload progress is available via `SetUploadCallback` / `SetUploadCallbackWithInterval`. Enabling `EnableForceChunkedEncoding` streams the body without buffering it in memory first. ### Simple file upload ```go client.R(). SetFile("avatar", "/path/to/photo.jpg"). SetFormData(map[string]string{"user": "alice"}). Post("https://example.com/upload") ``` ### Upload with progress callback (streaming via chunked encoding) ```go client.R(). EnableForceChunkedEncoding(). SetFile("report", "/path/to/large.pdf"). SetUploadCallbackWithInterval(func(info req.UploadInfo) { pct := float64(info.UploadedSize) / float64(info.FileSize) * 100 fmt.Printf("\r%.1f%% uploaded (%%d / %%d bytes)", pct, info.UploadedSize, info.FileSize) }, 200*time.Millisecond). Post("https://example.com/upload") ``` ### Multiple files via FileUpload structs (custom Content-Type) ```go client.R(). SetFileUpload( req.FileUpload{ParamName: "docs", FileName: "a.pdf"}, req.FileUpload{ParamName: "docs", FileName: "b.pdf"}, ). Post("https://example.com/batch-upload") ``` ``` -------------------------------- ### File Download Source: https://context7.com/imroc/req/llms.txt Explains how to download response bodies to a file or any io.Writer, with options for progress callbacks and setting a base output directory. ```APIDOC ## File Download — `SetOutputFile`, `SetOutput`, `SetDownloadCallback` To save a response body to disk set `SetOutputFile(path)` or provide any `io.Writer` via `SetOutput`. A download progress callback is available via `SetDownloadCallback`. `Client.SetOutputDirectory` sets a base directory applied to all relative output file paths. ### Download to file (relative to output directory) ```go client.C().SetOutputDirectory("/tmp/downloads") client.R(). SetOutputFile("go1.21.linux-amd64.tar.gz"). SetDownloadCallbackWithInterval(func(info req.DownloadInfo) { if info.Response.ContentLength > 0 { pct := float64(info.DownloadedSize) / float64(info.Response.ContentLength) * 100 fmt.Printf("\r%.1f%%", pct) } else { fmt.Printf("\r%%d bytes", info.DownloadedSize) } }, 500*time.Millisecond). Get("https://go.dev/dl/go1.21.0.linux-amd64.tar.gz") ``` ### Download to writer (e.g. os.Stdout or in-memory buffer) ```go client.R(). SetOutput(os.Stdout). Get("https://httpbin.org/uuid") ``` ``` -------------------------------- ### Impersonate Browser Fingerprints with req Source: https://context7.com/imroc/req/llms.txt Configure the client to mimic specific browser TLS ClientHello fingerprints, HTTP/2 settings, and header ordering. Use `SetTLSFingerprint` for fine-grained control with specific `utls.ClientHelloID`. ```go package main import ( "fmt" "github.com/imroc/req/v3" utls "github.com/refraction-networking/utls" ) func main() { // Impersonate Chrome 120 (sets TLS fingerprint + HTTP/2 settings + headers) chromeClient := req.C().ImpersonateChrome() resp := chromeClient.R().MustGet("https://tls.browserleaks.com/json") fmt.Println("Chrome fingerprint:", resp.GetStatus()) // Impersonate Firefox 120 ffClient := req.C().ImpersonateFirefox() resp = ffClient.R().MustGet("https://tls.browserleaks.com/json") fmt.Println("Firefox fingerprint:", resp.GetStatus()) // Impersonate Safari 16.6 safariClient := req.C().ImpersonateSafari() resp = safariClient.R().MustGet("https://tls.browserleaks.com/json") fmt.Println("Safari fingerprint:", resp.GetStatus()) // Specific TLS fingerprint only (without HTTP/2 or header adjustments) specificClient := req.C().SetTLSFingerprintChrome() _ = specificClient // Randomized TLS fingerprint to avoid detection randomClient := req.C().SetTLSFingerprintRandomized() _ = randomClient // Use a specific utls HelloID customClient := req.C().SetTLSFingerprint(utls.HelloEdge_106) _ = customClient } ```