Handling Responses
The Response struct represents the server’s reply and provides methods to access status codes, headers, body content, and cookies.
Structure
type Response struct {
client * Client
request * Request
cookie [] * fasthttp . Cookie
RawResponse * fasthttp . Response
}
Get response status details:
Status Code
Get the numeric HTTP status code:
resp , err := client . Get ( "https://httpbin.org/get" )
if err != nil {
panic ( err )
}
fmt . Printf ( "Status Code: %d \n " , resp . StatusCode ())
// Output: Status Code: 200
Signature:
func ( r * Response ) StatusCode () int
Status Message
Get the HTTP status message:
fmt . Printf ( "Status: %s \n " , resp . Status ())
// Output: Status: OK
Signature:
func ( r * Response ) Status () string
Protocol
Get the HTTP protocol version:
fmt . Printf ( "Protocol: %s \n " , resp . Protocol ())
// Output: Protocol: HTTP/1.1
Signature:
func ( r * Response ) Protocol () string
Access response headers:
contentType := resp . Header ( "Content-Type" )
fmt . Printf ( "Content-Type: %s \n " , contentType )
Signature:
func ( r * Response ) Header ( key string ) string
Iterate over all response headers:
import " strings "
for key , values := range resp . Headers () {
fmt . Printf ( " %s : %s \n " , key , strings . Join ( values , ", " ))
}
Signature:
func ( r * Response ) Headers () iter . Seq2 [ string , [] string ]
import " maps "
headers := maps . Collect ( resp . Headers ())
for key , values := range headers {
fmt . Printf ( " %s : %v \n " , key , values )
}
Header values are only valid until the response is released. Make copies if you need to store them.
Response Body
Get Body as Bytes
body := resp . Body ()
fmt . Printf ( "Body length: %d bytes \n " , len ( body ))
Signature:
func ( r * Response ) Body () [] byte
Get Body as String
Get the body as a trimmed string:
text := resp . String ()
fmt . Println ( text )
Signature:
func ( r * Response ) String () string
Stream Response Body
Read large responses as a stream:
c := client . New ()
c . SetStreamResponseBody ( true )
resp , err := c . Get ( "https://httpbin.org/bytes/1024" )
if err != nil {
panic ( err )
}
defer resp . Close ()
// Read from stream
buf := make ([] byte , 256 )
total , err := io . CopyBuffer ( io . Discard , resp . BodyStream (), buf )
if err != nil {
panic ( err )
}
fmt . Printf ( "Read %d bytes \n " , total )
Signature:
func ( r * Response ) BodyStream () io . Reader
func ( r * Response ) IsStreaming () bool
When using BodyStream(), calling Body() afterward may return an empty slice if the stream has been consumed.
Check if Streaming
if resp . IsStreaming () {
fmt . Println ( "Response is streaming" )
// Use resp.BodyStream() to read incrementally
} else {
fmt . Println ( "Response is buffered" )
// Use resp.Body() for direct access
}
Parse JSON
Unmarshal JSON responses:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
resp , err := client . Get ( "https://api.example.com/users/1" )
if err != nil {
panic ( err )
}
var user User
if err := resp . JSON ( & user ); err != nil {
panic ( err )
}
fmt . Printf ( "User: %s ( %s ) \n " , user . Name , user . Email )
Signature:
func ( r * Response ) JSON ( v any ) error
Parse JSON Array
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
resp , err := client . Get ( "https://api.example.com/users" )
if err != nil {
panic ( err )
}
var users [] User
if err := resp . JSON ( & users ); err != nil {
panic ( err )
}
for _ , user := range users {
fmt . Printf ( "User: %s \n " , user . Name )
}
Custom JSON Unmarshaler
Use a custom JSON unmarshaler:
import " github.com/goccy/go-json "
c := client . New ()
c . SetJSONUnmarshal ( json . Unmarshal )
resp , err := c . Get ( "https://api.example.com/users/1" )
if err != nil {
panic ( err )
}
var user User
if err := resp . JSON ( & user ); err != nil {
panic ( err )
}
Parse XML
Unmarshal XML responses:
type User struct {
XMLName xml . Name `xml:"user"`
ID int `xml:"id"`
Name string `xml:"name"`
Email string `xml:"email"`
}
resp , err := client . Get ( "https://api.example.com/users/1.xml" )
if err != nil {
panic ( err )
}
var user User
if err := resp . XML ( & user ); err != nil {
panic ( err )
}
fmt . Printf ( "User: %s \n " , user . Name )
Signature:
func ( r * Response ) XML ( v any ) error
Parse CBOR
Unmarshal CBOR responses:
type User struct {
ID int `cbor:"id"`
Name string `cbor:"name"`
}
resp , err := client . Get ( "https://api.example.com/users/1.cbor" )
if err != nil {
panic ( err )
}
var user User
if err := resp . CBOR ( & user ); err != nil {
panic ( err )
}
Signature:
func ( r * Response ) CBOR ( v any ) error
Cookies
Access cookies from the response:
resp , err := client . Get ( "https://httpbin.org/cookies/set/go/fiber" )
if err != nil {
panic ( err )
}
cookies := resp . Cookies ()
for _ , cookie := range cookies {
fmt . Printf ( " %s = %s \n " , string ( cookie . Key ()), string ( cookie . Value ()))
}
// Output: go = fiber
Signature:
func ( r * Response ) Cookies () [] * fasthttp . Cookie
Cookie values are only valid until the response is released. Make copies if you need to store them.
Save Response
Save the response body to a file or writer:
Save to File
resp , err := client . Get ( "https://httpbin.org/image/png" )
if err != nil {
panic ( err )
}
defer resp . Close ()
if err := resp . Save ( "/path/to/image.png" ); err != nil {
panic ( err )
}
Save to Writer
var buf bytes . Buffer
resp , err := client . Get ( "https://httpbin.org/get" )
if err != nil {
panic ( err )
}
defer resp . Close ()
if err := resp . Save ( & buf ); err != nil {
panic ( err )
}
fmt . Printf ( "Saved %d bytes \n " , buf . Len ())
Signature:
func ( r * Response ) Save ( v any ) error
When saving to a file, parent directories are created automatically if they don’t exist.
Error Handling
Check response status and handle errors:
resp , err := client . Get ( "https://api.example.com/users/999" )
if err != nil {
panic ( err )
}
defer resp . Close ()
if resp . StatusCode () != 200 {
fmt . Printf ( "Error: %s \n " , resp . Status ())
fmt . Printf ( "Body: %s \n " , resp . String ())
return
}
var user User
if err := resp . JSON ( & user ); err != nil {
fmt . Printf ( "Failed to parse JSON: %v \n " , err )
return
}
Check Status Code Ranges
switch {
case resp . StatusCode () >= 200 && resp . StatusCode () < 300 :
fmt . Println ( "Success" )
case resp . StatusCode () >= 400 && resp . StatusCode () < 500 :
fmt . Println ( "Client error" )
case resp . StatusCode () >= 500 :
fmt . Println ( "Server error" )
}
Resource Management
Properly release responses to avoid memory leaks:
Close Response
Release both request and response to the pool:
resp , err := client . Get ( "https://httpbin.org/get" )
if err != nil {
panic ( err )
}
defer resp . Close ()
// Use the response
fmt . Println ( resp . String ())
Signature:
func ( r * Response ) Close ()
Manual Pool Management
resp := client . AcquireResponse ()
defer client . ReleaseResponse ( resp )
// Configure and use response
Signature:
func AcquireResponse () * Response
func ReleaseResponse ( resp * Response )
Always call resp.Close() or client.ReleaseResponse(resp) when done with a response. Do not use responses after releasing them.
Access Raw Response
Access the underlying fasthttp response:
resp , err := client . Get ( "https://httpbin.org/get" )
if err != nil {
panic ( err )
}
defer resp . Close ()
// Access raw fasthttp response
rawResp := resp . RawResponse
fmt . Printf ( "Connection close: %v \n " , rawResp . Header . ConnectionClose ())
Examples
Download and Save File
c := client . New ()
c . SetStreamResponseBody ( true )
resp , err := c . Get ( "https://example.com/largefile.zip" )
if err != nil {
panic ( err )
}
defer resp . Close ()
if err := resp . Save ( "/downloads/largefile.zip" ); err != nil {
panic ( err )
}
fmt . Println ( "File downloaded successfully" )
Parse Nested JSON
type Repository struct {
Name string `json:"name"`
FullName string `json:"full_name"`
Description string `json:"description"`
Owner struct {
Login string `json:"login"
} ` json : "owner"`
}
resp, err := client.Get("https://api.github.com/repos/gofiber/fiber")
if err != nil {
panic(err)
}
defer resp.Close()
var repo Repository
if err := resp.JSON(&repo); err != nil {
panic(err)
}
fmt.Printf("Repository: %s \n", repo.FullName)
fmt.Printf("Owner: %s \n", repo.Owner.Login)
fmt.Printf("Description: %s \n", repo.Description)
Handle API Errors
type APIError struct {
Error string `json:"error"`
Message string `json:"message"`
}
resp , err := client . Get ( "https://api.example.com/users/999" )
if err != nil {
panic ( err )
}
defer resp . Close ()
if resp . StatusCode () != 200 {
var apiErr APIError
if err := resp . JSON ( & apiErr ); err != nil {
fmt . Printf ( "Failed to parse error response: %v \n " , err )
return
}
fmt . Printf ( "API Error: %s - %s \n " , apiErr . Error , apiErr . Message )
return
}
var user User
if err := resp . JSON ( & user ); err != nil {
panic ( err )
}
Next Steps
Request/Response Hooks Intercept and modify responses
Examples See complete working examples