---
sidebar_label: "Request & Response"
title: "Request and Response - CyberGo HTTPC | Options & Responses"
description: "HTTPC request and response guide: package functions and client requests, WithHeader/WithJSON options, Bearer auth, query parameters, and context control."
sidebar_position: 2
---

# Request and Response

## Sending Requests

### Package-Level Functions

Send requests directly without creating a client:

```go
result, err := httpc.Get("https://api.example.com/data")
if err != nil {
    log.Fatal(err)
}

fmt.Println(result.StatusCode())
fmt.Println(result.Body())
```

Supported HTTP methods: `Get`, `Post`, `Put`, `Patch`, `Delete`, `Head`, `Options`.

### Client Instance

```go
client, err := httpc.New()
if err != nil {
    log.Fatal(err)
}
defer client.Close()

result, err := client.Get("https://api.example.com/data")
```

### Generic Request Method

```go
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

result, err := httpc.Request(ctx, "GET", "https://api.example.com/data")
```

## Request Options

### Headers

```go
result, err := client.Get(url,
    httpc.WithHeader("Authorization", "Bearer token"),
    httpc.WithHeader("X-Custom", "value"),
    httpc.WithHeaderMap(map[string]string{
        "Accept":        "application/json",
        "X-Request-ID":  "123",
    }),
    httpc.WithUserAgent("my-app/1.0"),
)
```

### Request Body

```go
// JSON
result, err := client.Post(url, httpc.WithJSON(map[string]any{
    "name": "test",
}))

// XML
result, err := client.Post(url, httpc.WithXML(data))

// Form
result, err := client.Post(url, httpc.WithForm(map[string]string{
    "username": "admin",
    "password": "secret",
}))

// Binary (default application/octet-stream)
result, err := client.Post(url, httpc.WithBinary(data))
// Specify type
result, err := client.Post(url, httpc.WithBinary(data, "image/png"))

// Auto-detect type
result, err := client.Post(url, httpc.WithBody(data))
// string -> text/plain; charset=utf-8, []byte -> application/octet-stream,
// map[string]string -> application/x-www-form-urlencoded,
// *FormData -> multipart/form-data, io.Reader -> passed through,
// other -> application/json
// Optional explicit specification: httpc.WithBody(data, httpc.BodyJSON)
```

### Query Parameters

```go
result, err := client.Get(url,
    httpc.WithQuery("page", 1),
    httpc.WithQuery("limit", 10),
)

// Or use Map
result, err := client.Get(url,
    httpc.WithQueryMap(map[string]any{
        "page":  1,
        "limit": 10,
    }),
)
```

### Authentication

```go
// Bearer Token
result, err := client.Get(url, httpc.WithBearerToken("my-token"))

// Basic Auth
result, err := client.Get(url, httpc.WithBasicAuth("user", "pass"))
```

### Cookies

```go
result, err := client.Get(url,
    httpc.WithCookie(http.Cookie{Name: "session", Value: "abc"}),
    httpc.WithCookieMap(map[string]string{"session": "abc", "lang": "en"}),
    httpc.WithCookieString("session=abc; lang=en"),
)
```

### Request Control

```go
// Timeout
result, err := client.Get(url, httpc.WithTimeout(10*time.Second))

// Retry
result, err := client.Get(url, httpc.WithMaxRetries(5))

// Redirects
result, err := client.Get(url,
    httpc.WithFollowRedirects(false),    // Disable redirects
)
```

:::tip WithMaxRedirects(0) does not disable
`WithMaxRedirects(0)` does **not** disable redirects -- the engine treats `0` as "unset" and falls back to the default of 10. To fully disable redirect following, use `WithFollowRedirects(false)`.
:::

### Callbacks

```go
result, err := client.Get(url,
    httpc.WithOnRequest(func(req httpc.RequestMutator) error {
        log.Printf("Sending request: %s %s", req.Method(), req.URL())
        return nil
    }),
    httpc.WithOnResponse(func(resp httpc.ResponseMutator) error {
        log.Printf("Received response: %d", resp.StatusCode())
        return nil
    }),
)
```

## Response Handling

```go
result, err := client.Get("https://api.example.com/users/1")
if err != nil {
    log.Fatal(err)
}

// Status check
result.StatusCode()     // 200
result.IsSuccess()      // true (2xx)
result.IsRedirect()     // false (3xx)
result.IsClientError()  // false (4xx)
result.IsServerError()  // false (5xx)

// Read response
result.Body()           // string
result.RawBody()        // []byte
result.Proto()          // "HTTP/1.1"

// JSON parsing
var user User
if err := result.Unmarshal(&user); err != nil {
    log.Fatal(err)
}

// Cookies
cookie := result.GetCookie("session")
if cookie != nil {
    fmt.Println(cookie.Value)
}

// Request metadata
fmt.Println(result.Meta.Duration)       // Request duration
fmt.Println(result.Meta.Attempts)       // Retry count
fmt.Println(result.Meta.RedirectCount)  // Redirect count
```

## Context Control

```go
// Timeout control
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := httpc.Request(ctx, "GET", url)

// Cancel control
ctx, cancel := context.WithCancel(context.Background())
go func() {
    time.Sleep(5 * time.Second)
    cancel() // Cancel after 5 seconds
}()
result, err := httpc.Request(ctx, "GET", url)
```

## Streaming Responses

`WithStreamBody(true)` is an internal mechanism used during file downloads to avoid caching the entire response body in memory. When enabled, the response body is not read into `Result` (`Body()` and `RawBody()` return empty values).

:::warning
`WithStreamBody(true)` is used internally by the file download API. For streaming response content, use the [File Download API](./file-transfer).
:::

For downloading large files, use the download API:

```go
cfg := httpc.DefaultDownloadConfig()
cfg.FilePath = "/path/to/file"
result, err := client.Download(context.Background(), url, cfg)
```

## Response Decompression

HTTPC automatically handles decompression of gzip, deflate, and other content encodings. You can limit the decompressed body size through security configuration to prevent decompression bomb attacks:

```go
cfg := httpc.DefaultConfig()
cfg.Security.MaxResponseBodySize = 10 * 1024 * 1024      // Response body limit: enforced on streaming download; fallback for the decompressed limit in non-streaming reads
cfg.Security.MaxDecompressedBodySize = 100 * 1024 * 1024  // Max decompressed body 100MB
```

| Setting | Default | Description |
|---------|---------|-------------|
| `MaxResponseBodySize` | 10MB | Streaming download response body limit; falls back to the decompressed limit in non-streaming reads |
| `MaxDecompressedBodySize` | 100MB | Decompressed response body size limit |

The compressed body has a separate 100MB hard cap (`maxCompressedSize`, not configurable) that defends against decompression bombs, independent of `MaxResponseBodySize`.

When the limit is exceeded, an error containing `"exceeds limit"` is returned, which can be handled via the `ClientError` type. `ErrResponseBodyTooLarge` is returned when `Result.Unmarshal()` parses a response body exceeding the 50MB JSON size limit (independent of `MaxResponseBodySize`).

## Next Steps

- [File Upload and Download](./file-transfer) - File transfer guide
- [Domain Client and Sessions](./domain-session) - Session management
- [Request Options API](../api-reference/core/options) - Complete options reference
- [Result API](../api-reference/core/result) - Response handling reference
