Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gofiber/fiber/llms.txt

Use this file to discover all available pages before exploring further.

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
}

Status Information

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

Headers

Access response headers:

Get Single Header

contentType := resp.Header("Content-Type")
fmt.Printf("Content-Type: %s\n", contentType)
Signature:
func (r *Response) Header(key string) string

Get All Headers

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]

Collect Headers to Map

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