httplib is a package that provides a simple and flexible way to create and send HTTP requests in Go. This package includes features like setting headers, customizing the request body, configuring the timeout, adding middleware, rate limiting, and handling retries with backoff. If you are looking for Guzzle or Axios for Golang, you are in the right place.
- Creating a new request
- Adding headers
- Adding a JSON body
- Adding a custom body
- Setting the timeout
- Using a custom HTTP client
- Middleware
- Reading a JSON response
- Rate limiting
- Retries with backoff
- Sending the request
- Chaining requests
- Sending requests asynchronously
- File upload
To create a new request, use the NewRequestBuilder
function:
rb := httplib.NewRequestBuilder("GET", "https://api.example.com/data")
To add a JSON body to the request, use the WithJSONBody
method:
data := map[string]interface{}{
"key": "value",
}
rb, err := rb.WithJSONBody(data)
To add a custom body to the request, use the WithCustomBody
method:
rb.WithCustomBody(strings.NewReader("<xml>data</xml>"))
To set the timeout for the request, use the WithTimeout
method:
rb.WithTimeout(10 * time.Second)
To use a custom HTTP client for the request, use the WithClient
method:
rb.WithClient(myCustomClient)
To add a middleware function that will be executed on the response before returning it to the caller, use the Use method:
rb.Use(myMiddlewareFunction)
To read the response body and unmarshal it into a target object, use the ReadJSONResponse
method:
response, err := rb.Send()
if err == nil {
err = rb.ReadJSONResponse(response, &myTargetObject)
}
To set a rate limiter for the request, use the WithRateLimiter method:
rb.WithRateLimiter(10, 5) // 10 requests per second with a burst of 5
To set the number of retries and the backoff function for the request, use the WithRetry method:
rb.WithRetry(3, httplib.ExponentialBackoff)
To send the request and get the response, use the Send method:
response, err := rb.Send()
To send a request and then use the response to build another request, use the SendAndChain method:
response, err := rb.SendAndChain(myChainingFunction)
To send a request asynchronously and get a channel that will contain the response, use the SendAsync method:
resultChan := rb.SendAsync()
package main
import (
"fmt"
"time"
"github.com/joefazee/httplib"
)
type ApiResponse struct {
Data []string `json:"data"`
}
func main() {
rb := httplib.NewRequestBuilder("GET", "https://api.example.com/data")
rb.WithHeader("Authorization", "Bearer <your-token>")
rb.WithTimeout(10 * time.Second)
response, err := rb.Send()
if err != nil {
fmt.Println("Error:", err)
return
}
var apiResponse ApiResponse
err = rb.ReadJSONResponse(response, &apiResponse)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Data:", apiResponse.Data)
}
package main
import (
"fmt"
"time"
"github.com/joefazee/httplib"
)
type PostData struct {
Title string `json:"title"`
Body string `json:"body"`
}
func main() {
postData := &PostData{
Title: "My Title",
Body: "This is the body of my post.",
}
rb := httplib.NewRequestBuilder("POST", "https://api.example.com/posts")
rb.WithHeader("Authorization", "Bearer <your-token>")
rb.WithTimeout(10 * time.Second)
_, err := rb.WithJSONBody(postData)
if err != nil {
fmt.Println("Error:", err)
return
}
response, err := rb.Send()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Status:", response.Status)
}
package main
import (
"fmt"
"time"
"github.com/joefazee/httplib"
)
type ApiResponse struct {
Data []string `json:"data"`
}
func main() {
rb := httplib.NewRequestBuilder("GET", "https://api.example.com/data")
rb.WithHeader("Authorization", "Bearer <your-token>")
rb.WithTimeout(10 * time.Second)
rb.WithRateLimiter(5, 2) // 5 requests per second with a burst of 2
rb.WithRetry(3, httplib.ExponentialBackoff)
response, err := rb.Send()
if err != nil {
fmt.Println("Error:", err)
return
}
var apiResponse ApiResponse
err = rb.ReadJSONResponse(response, &apiResponse)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Data:", apiResponse.Data)
}
package main
import (
"fmt"
"github.com/joefazee/httplib"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
Email string `json:"email"`
}
type Todo struct {
ID int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
UserId int `json:"userId"`
}
func main() {
// Create a new GET request to retrieve a user
userRB := httplib.NewRequestBuilder("GET", "https://jsonplaceholder.typicode.com/users/1")
// Send the request and chain another request to retrieve the user's first to-do item
response, err := userRB.SendAndChain(func(res *http.Response) (*httplib.RequestBuilder, error) {
// Read JSON data from the response into a User struct
var user User
err := userRB.ReadJSONResponse(res, &user)
if err != nil {
return nil, err
}
// Print the retrieved user information
fmt.Printf("Retrieved User: %+v\n", user)
// Create a new GET request to retrieve the user's first to-do item
todoURL := fmt.Sprintf("https://jsonplaceholder.typicode.com/todos?userId=%d", user.ID)
todoRB := httplib.NewRequestBuilder("GET", todoURL)
return todoRB, nil
})
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
// Read JSON data from the response into a Todo struct
var todos []Todo
err = httplib.NewRequestBuilder("", "").ReadJSONResponse(response, &todos)
if err != nil {
log.Fatal(err)
}
// Print the retrieved to-do item
fmt.Printf("Retrieved To-do Item: %+v\n", todos[0])
}
package main
import (
"fmt"
"time"
"github.com/joefazee/httplib"
)
type ApiResponse struct {
Data []string `json:"data"`
}
func main() {
rb := httplib.NewRequestBuilder("GET", "https://api.example.com/data")
rb.WithHeader("Authorization", "Bearer <your-token>")
rb.WithTimeout(10 * time.Second)
rb.WithRateLimiter(5, 2) // 5 requests per second with a burst of 2
rb.WithRetry(3, httplib.ExponentialBackoff)
response, err := rb.Send()
if err != nil {
fmt.Println("Error:", err)
return
}
var apiResponse ApiResponse
err = rb.ReadJSONResponse(response, &apiResponse)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Data:", apiResponse.Data)
}
package main
import (
"fmt"
"sync"
"github.com/joefazee/httplib"
)
func fetchUrl(url string, wg *sync.WaitGroup) {
defer wg.Done()
rb := httplib.NewRequestBuilder("GET", url)
resultChan := rb.SendAsync()
result := <-resultChan
if result.Error != nil {
fmt.Println("Error:", result.Error)
return
}
fmt.Println("Fetched", url, "Status:", result.Response.Status)
}
- First, create a simple HTTP server to handle file uploads:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
err := r.ParseMultipartForm(32 << 20) // 32MB max memory
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
file, _, err := r.FormFile("file")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
defer file.Close()
fileContent, err := ioutil.ReadAll(file)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
fmt.Println("Received file content:", string(fileContent))
w.WriteHeader(http.StatusOK)
})
fmt.Println("Starting server on :8080...")
http.ListenAndServe(":8080", nil)
}
This code creates a simple HTTP server that listens on port 8080 and handles file uploads at the /upload endpoint.
- Next, create a client application to upload a file to the server using the httplib package:
package main
import (
"fmt"
"github.com/joefazee/httplib"
"log"
)
func main() {
filePath := "/path/to/your/file.txt"
rb := httplib.NewRequestBuilder("POST", "http://localhost:8080/upload")
rb, err := rb.WithFile("file", filePath)
if err != nil {
log.Fatal(err)
}
response, err := rb.Send()
if err != nil {
log.Fatal(err)
}
fmt.Println("File uploaded:", response.StatusCode)
}
Install the AWS SDK for Go using:
go get -u github.com/aws/aws-sdk-go
Use the following code to generate a pre-signed URL:
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/joefazee/httplib"
"log"
"time"
)
func main() {
// Initialize a new session
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
})
if err != nil {
log.Fatal(err)
}
// Create a new S3 service client
s3Client := s3.New(sess)
// Generate the pre-signed URL
req, _ := s3Client.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("your-bucket-name"),
Key: aws.String("your-object-key"),
})
presignedURL, err := req.Presign(15 * time.Minute)
if err != nil {
log.Fatal(err)
}
fmt.Println("Pre-signed URL:", presignedURL)
// Upload the file using the httplib package
filePath := "/path/to/your/file.txt"
rb := httplib.NewRequestBuilder("PUT", presignedURL)
rb, err = rb.WithFile("file", filePath)
if err != nil {
log.Fatal(err)
}
response, err := rb.Send()
if err != nil {
log.Fatal(err)
}
fmt.Println("File uploaded to S3:", response.StatusCode)
}