HTTP Client
Introduction
In software development, there are many instances when you need to call an API to fetch data— whether it's connecting to a microservice or accessing a third-party API. In such cases, Goravel offers an easy-to-use, expressive, and minimalist API built on the standard net/http
library, all designed to enhance the developer experience.
Configuration
Goravel's HTTP client is built on top of the net/http.Client
for making HTTP requests. If you need to tweak its internal settings, just update the client
property in the config/http.go
file. Here are the available configuration options:
base_url
: Sets the root URL for relative paths. Automatically prefixes requests that don't start withhttp://
orhttps://
.timeout
(DEFAULT
:30s
): Global timeout duration for complete request lifecycle (connection + any redirects + reading the response body). A Timeout of zero means no timeout.max_idle_conns
: Maximum number of idle (keep-alive) connections across all hosts. Zero means no limit.max_idle_conns_per_host
: Maximum idle (keep-alive) connections to keep per-hostmax_conns_per_host
: Limits the total number of connections per host, including connections in the dialing, active, and idle states. Zero means no limit.idle_conn_timeout
: Maximum amount of the time of an idle (keep-alive) connection will remain idle before closing itself.
"client": map[string]any{
"base_url": config.GetString("HTTP_CLIENT_BASE_URL"), // "https://api.example.com"
"timeout": config.GetDuration("HTTP_CLIENT_TIMEOUT"), // 30 * time.Second
"max_idle_conns": config.GetInt("HTTP_CLIENT_MAX_IDLE_CONNS"), // 100
"max_idle_conns_per_host": config.GetInt("HTTP_CLIENT_MAX_IDLE_CONNS_PER_HOST"), // 10
"max_conns_per_host": config.GetInt("HTTP_CLIENT_MAX_CONN_PER_HOST"), // 0
"idle_conn_timeout": config.GetDuration("HTTP_CLIENT_IDLE_CONN_TIMEOUT"), // 90 * time.Second
}
Making Requests
The Http facade provides a convenient way to make HTTP requests using familiar verbs: GET
, POST
, PUT
, DELETE
, PATCH
, HEAD
, and OPTIONS
.
Example: GET Request
import "github.com/goravel/framework/facades"
response, err := facades.Http().Get("https://example.com")
Each HTTP verb method returns a response
of type framework/contracts/http/client.Response
and an err
if the request fails.
Response Interface
The framework/contracts/http/client.Response
interface provides the following methods to interact with the HTTP response:
type Response interface {
Body() (string, error) // Get the response body as a string
ClientError() bool // Check if the status code is in the 4xx range
Cookie(name string) *http.Cookie // Get a specific cookie
Cookies() []*http.Cookie // Get all response cookies
Failed() bool // Check if the status code is not in the 2xx range
Header(name string) string // Get the value of a specific header
Headers() http.Header // Get all response headers
Json() (map[string]any, error) // Decode the response body as JSON into a map
Redirect() bool // Check if the response is a redirect (3xx status code)
ServerError() bool // Check if the status code is in the 5xx range
Status() int // Get the HTTP status code
Successful() bool // Check if the status code is in the 2xx range
/* status code related methods */
OK() bool // 200 OK
Created() bool // 201 Created
Accepted() bool // 202 Accepted
NoContent() bool // 204 No Content
MovedPermanently() bool // 301 Moved Permanently
Found() bool // 302 Found
BadRequest() bool // 400 Bad Request
Unauthorized() bool // 401 Unauthorized
PaymentRequired() bool // 402 Payment Required
Forbidden() bool // 403 Forbidden
NotFound() bool // 404 Not Found
RequestTimeout() bool // 408 Request Timeout
Conflict() bool // 409 Conflict
UnprocessableEntity() bool // 422 Unprocessable Entity
TooManyRequests() bool // 429 Too Many Requests
}
URI Templates
URI Templates let you build dynamic request URLs using placeholders. You can define these placeholders in your URL and then provide the values to replace them before making the request. To achieve this, you can use WithUrlParameter
for single parameters or WithUrlParameters
for multiple parameters.
response, err := facades.Http().
WithUrlParameter("id", "123").
Get("https://api.example.com/users/{id}")
// or
response, err := facades.Http().
WithUrlParameters(map[string]string{
"bookId": "456",
"chapterNumber": "7",
}).
Get("https://api.example.com/books/{bookId}/chapters/{chapterNumber}")
Request Query Parameters
Add query parameters to your requests using WithQueryParameter
for single parameters or WithQueryParameters
for multiple parameters via a map.
response1, err1 := facades.Http().
WithQueryParameter("sort", "name").
Get("https://api.example.com/users")
// Resulting URL: https://api.example.com/users?sort=name
// or multiple query parameters
response2, err2 := facades.Http().
WithQueryParameters(map[string]string{
"page": "2",
"pageSize": "10",
}).
Get("https://api.example.com/products")
// Resulting URL: https://api.example.com/products?page=2&pageSize=10
You can also add query parameters directly as a formatted string using WithQueryString
:
response, err := facades.Http().
WithQueryString("filter=active&order=price").
Get("https://api.example.com/items")
Sending a Request Body
For HTTP verbs like POST
, PUT
, PATCH
and DELETE
accept io.Reader
as the second argument. To simplify building payloads, the framework provides utility methods for constructing request bodies.
import "github.com/goravel/framework/support/http"
builder := http.NewBody().SetField("name", "krishan")
body, err := builder.Build()
response, err := facades.Http().WithHeader("Content-Type", body.ContentType()).Post("https://example.com/users", body)
Headers
You can add headers to your requests using WithHeader
for a single header or WithHeaders
for multiple headers provided as a map.
response, err := facades.Http().
WithHeader("X-Custom-Header", "value").
Get("https://api.example.com")
// Add multiple headers
response, err = facades.Http().
WithHeaders( map[string]string{
"Content-Type": "application/json",
"Accept": "application/xml",
}).
Get("https://api.example.com")
You may use the Accept
method to specify the content type that your application is expecting in response to your request:
response, err := facades.Http().
Accept("application/xml").
Get("https://api.example.com")
For convenience, you can use AcceptJson
to quickly specify that you expect the API response to be in application/json
format:
response, err := facades.Http().
AcceptJson().
Get("https://api.example.com/data")
To replace all existing headers with a new set, use ReplaceHeaders
:
response, err := facades.Http().
ReplaceHeaders(map[string]string{
"Authorization": "Bearer token",
}).
Get("https://api.example.com")
You can remove a specific header using WithoutHeader
or clear all headers with FlushHeaders
.
response, err := facades.Http().
WithoutHeader("X-Previous-Header").
Get("https://api.example.com")
// flush all headers
response, err := facades.Http().
FlushHeaders().
Get("https://api.example.com")
Authentication
You can specify basic authentication using the WithBasicAuth
method:
response, err := facades.Http().
WithBasicAuth("username", "password").
Get("https://api.example.com/protected")
Bearer Tokens
To quickly add a bearer token to the request's Authorization
header, you can use the WithToken
method:
response, err := facades.Http().
WithToken("your_bearer_token").
Get("https://api.example.com/api/resource")
TIP
The WithToken
method also accepts an optional second argument to specify the token type (e.g., "Bearer", "Token"). If no type is provided, it defaults to "Bearer".
response, err := facades.Http().
WithToken("custom_token", "Token").
Get("https://api.example.com/api/resource")
To remove the bearer token from the request, use the WithoutToken
method:
response, err := facades.Http().
WithoutToken().
Get("https://api.example.com/api/resource")
Context
You can use WithContext
to make your HTTP requests context-aware. This allows you to control the lifecycle of a request, for instance, by setting timeouts or enabling cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
response, err := facades.Http().WithContext(ctx).Get("https://example.com")
Bind Response
You can use the Bind
method directly on the Http
facade to specify the struct that the response should be bound to.
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
var user User
response, err := facades.Http().Bind(&user).AcceptJson().Get("https://jsonplaceholder.typicode.com/users/1")
if err != nil {
fmt.Println("Error making request:", err)
return
}
fmt.Printf("User ID: %d, Name: %s\n", user.ID, user.Name)
}
Cookie
To send cookies with your HTTP requests, you can use WithCookie
for a single cookie or WithCookies
for multiple cookies.
response, err := facades.Http().
WithCookie(&http.Cookie{Name: "user_id", Value: "123"}).
Get("https://example.com/profile")
// multiple cookies
response, err := facades.Http().
WithCookies([]*http.Cookie{
{Name: "session_token", Value: "xyz"},
{Name: "language", Value: "en"},
}).
Get("https://example.com/dashboard")
To prevent specific cookies from being sent with your request, you can use WithoutCookie
.
response, err := facades.Http().
WithoutCookie("language").
Get("https://example.com")