Hey there, fellow Gophers! 👋
Ever found yourself wrestling with HTTP requests in Go? Maybe you're building a service that needs to talk to multiple APIs, or you're just tired of writing boilerplate HTTP client code. Well, I've got something that might make your life easier!
In this guide, I'll show you how to leverage go-resty
- a feature-rich HTTP client library - within the GoFrame framework to make your API integrations smooth and maintainable. Trust me, your future self will thank you!
Why go-resty? 🤔
Before we dive in, you might be wondering: "Why not just use the standard net/http
package?" Good question! While Go's standard HTTP client is powerful, go-resty
adds a layer of convenience with:
- Chainable methods (bye-bye verbose code!)
- Built-in retry mechanisms
- Automatic response unmarshalling
- Request/response middleware support
- And much more!
Getting Started 🚀
First things first, let's get our tools ready. You'll need Go installed (I assume you've got that covered!), then run:
go install github.com/gogf/gf/v2/cmd/gf@latest
go get github.com/go-resty/resty/v2
Your First Request 🎯
Let's start with something simple. Here's how you make a GET request:
import (
"github.com/go-resty/resty/v2"
"github.com/gogf/gf/v2/frame/g"
)
func main() {
// Create a client (tip: reuse this client!)
client := resty.New()
// Make a request
resp, err := client.R().
SetQueryParams(map[string]string{
"page": "1",
"limit": "10",
}).
Get("https://api.example.com/users")
if err != nil {
g.Log().Errorf(ctx, "Oops! Something went wrong: %v", err)
return
}
// Use the response
fmt.Printf("Status: %v\n", resp.Status())
fmt.Printf("Body: %v\n", resp.String())
}
Pretty clean, right? 😎
POSTing Data Made Easy 📬
Need to send some data? Here's how you make a POST request:
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(map[string]interface{}{
"username": "gopher",
"email": "gopher@go.dev",
}).
Post("https://api.example.com/users")
Debug Like a Pro 🔍
During development, you'll want to see what's going on with your requests. Just add:
client.SetDebug(true)
Now you'll see detailed logs of your requests and responses. Super helpful for debugging!
Handling Timeouts Like a Boss ⏱️
In the real world, things go wrong. Here's how to handle timeouts gracefully:
// Global timeout for all requests
client := resty.New().
SetTimeout(5 * time.Second)
// Or for a specific request
resp, err := client.R().
SetTimeout(3 * time.Second).
Get("https://api.example.com/users")
// Check for timeout errors
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
fmt.Println("Request timed out! 😱")
return
}
fmt.Printf("Other error: %v\n", err)
}
Retry Mechanism: Because Sometimes Things Fail 🔄
Here's a real-world example of setting up retries for flaky APIs:
client.
SetRetryCount(3).
SetRetryWaitTime(5 * time.Second).
SetRetryMaxWaitTime(20 * time.Second).
AddRetryCondition(
func(r *resty.Response, err error) bool {
return r.StatusCode() >= 500 // Retry on server errors
},
)
Authentication Made Simple 🔐
Need to add auth headers to every request? Use middleware:
client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
req.SetHeader("Authorization", "Bearer " + getToken())
return nil
})
Pro Tips 💡
- Reuse Clients: Create one client and reuse it. Don't create a new client for every request!
- Context is Your Friend: Use context for better control over request lifecycles:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.R().
SetContext(ctx).
Get("https://api.example.com/users")
- Handle Responses Properly: Always check both the error AND the status code:
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
if resp.StatusCode() >= 400 {
return fmt.Errorf("bad status: %s", resp.Status())
}
Real-World Example: Building a Weather Service 🌤️
Let's put it all together with a practical example - a weather service that handles retries, timeouts, and error cases:
func NewWeatherService() *WeatherService {
client := resty.New().
SetTimeout(10 * time.Second).
SetRetryCount(3).
SetRetryWaitTime(1 * time.Second).
SetHostURL("https://api.weatherapi.com/v1")
return &WeatherService{client: client}
}
func (s *WeatherService) GetCurrentWeather(ctx context.Context, city string) (*WeatherData, error) {
var result WeatherData
resp, err := s.client.R().
SetQueryParam("q", city).
SetQueryParam("key", os.Getenv("WEATHER_API_KEY")).
SetResult(&result).
SetContext(ctx).
Get("/current.json")
if err != nil {
return nil, fmt.Errorf("weather request failed: %w", err)
}
if resp.IsError() {
return nil, fmt.Errorf("weather API error: %s", resp.String())
}
return &result, nil
}
Wrapping Up 🎁
go-resty with GoFrame is a powerful combination for handling HTTP requests in Go. It provides a clean API while giving you all the tools you need for production-ready code.
Remember:
- Keep your clients reusable
- Set appropriate timeouts
- Use retries for resilience
- Handle errors gracefully
Now go forth and build awesome things! 🚀
Want More? 📚
- Check out the go-resty docs for more features
- Explore GoFrame for full-stack development
- Follow me for more Go tips and tricks!
Did this help you? Have questions? Drop a comment below! 👇
Top comments (0)