HTTP Client - WunderGraph

Features

Basic Usage

package main

import (
    "context"
    "fmt"
    "time"

"github.com/wundergraph/cosmo/router-plugin/httpclient"
)

func main() {
    // Create HTTP client with configuration options
    client := httpclient.New(
        httpclient.WithBaseURL("https://api.example.com"),
        httpclient.WithTimeout(10 * time.Second),
        httpclient.WithHeader("Accept", "application/json"),
    )

// Create a context
    ctx := context.Background()

// Make a GET request
    resp, err := client.Get(ctx, "/users/1")
    if err != nil {
        panic(err)
    }

// Check if the request was successful
    if !resp.IsSuccess() {
        fmt.Printf("Request failed with status code: %d\n", resp.StatusCode)
        return
    }

// Parse the response into a struct using generics
    type User struct {
        ID    int    `json:"id"`
        Name  string `json:"name"`
        Email string `json:"email"`
    }

user, err := httpclient.UnmarshalTo[User](resp)
    if err != nil {
        panic(err)
    }

fmt.Printf("User: %s (Email: %s)\n", user.Name, user.Email)
}

Advanced Usage

Middleware

The client supports middleware for request customization:

// Create a client with middleware
client := httpclient.New(
    httpclient.WithBaseURL("https://api.example.com"),
    httpclient.WithMiddleware(httpclient.AuthBearerMiddleware("your-token")),
    httpclient.WithMiddleware(httpclient.UserAgentMiddleware("MyApp/1.0")),
    httpclient.WithTracing(),
)

Request-specific options

You can add headers or other options to specific requests:

// Make a request with specific headers
resp, err := client.Get(ctx, "/users/1",
    httpclient.WithRequestHeader("X-Request-ID", "12345"),
)

POST requests with JSON body

// Create request body
newUser := struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}{
    Name:  "John Doe",
    Email: "john@example.com",
}

// Send POST request
resp, err := client.Post(ctx, "/users", newUser)

Middleware Implementations

The package includes several built-in middleware implementations:

Custom Middleware

You can create your own middleware:

// Create a custom middleware
customMiddleware := func(req *http.Request) (*http.Request, error) {
    // Customize the request
    req.Header.Set("X-Custom-Header", "custom-value")
    return req, nil
}

// Add the middleware to the client
client := httpclient.New(
    httpclient.WithMiddleware(customMiddleware),
)

Error Handling

The client returns comprehensive errors that can be unwrapped:

resp, err := client.Get(ctx, "/users/1")
if err != nil {
    // Check for specific error types
    var urlErr *url.Error
    if errors.As(err, &urlErr) {
        fmt.Printf("URL error: %v\n", urlErr)
    } else {
        fmt.Printf("Other error: %v\n", err)
    }
    return
}

Inbuilt Tracing

When using tracing alongside an http client, you can enable tracing using

httpclient.WithTracing()

Which will create spans for your http calls. Note that in case of using retry, it will only create one span for the entire operation, and not per retry.

Response Helpers

The Response type provides helper methods: