> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Response

> Send responses with helpers that manage headers, status codes, and body writes.

Every handler in Mizu uses a `*mizu.Ctx` to send responses. The context provides helper methods for common response types like JSON, HTML, and files, while still giving you access to the underlying `http.ResponseWriter` when needed.

## Response basics

Each response has three parts:

1. **Status code** - HTTP status like 200, 404, or 500
2. **Headers** - Metadata like Content-Type and Cache-Control
3. **Body** - The actual data sent to the client

Mizu's response helpers handle all three. You typically just call one method and return.

## Text responses

Send plain text with `c.Text()`:

```go theme={null}
func handler(c *mizu.Ctx) error {
    return c.Text(200, "Hello, world!")
}
```

This sets:

* Status: 200
* Content-Type: `text/plain; charset=utf-8`
* Body: "Hello, world!"

If the string isn't valid UTF-8, it's sent as `application/octet-stream`.

## JSON responses

Send structured data with `c.JSON()`:

```go theme={null}
func handler(c *mizu.Ctx) error {
    user := User{ID: "123", Name: "Alice"}
    return c.JSON(200, user)
}

// Works with maps too
func status(c *mizu.Ctx) error {
    return c.JSON(200, map[string]any{
        "status": "ok",
        "count":  42,
    })
}
```

This sets:

* Status: 200
* Content-Type: `application/json; charset=utf-8`
* Body: JSON-encoded data

## HTML responses

Send HTML content with `c.HTML()`:

```go theme={null}
func handler(c *mizu.Ctx) error {
    return c.HTML(200, "<h1>Welcome</h1><p>Hello from Mizu!</p>")
}
```

For templates, use Go's `html/template`:

```go theme={null}
var tmpl = template.Must(template.New("page").Parse(`
    <h1>{{.Title}}</h1>
    <p>{{.Message}}</p>
`))

func handler(c *mizu.Ctx) error {
    c.Header().Set("Content-Type", "text/html; charset=utf-8")
    return tmpl.Execute(c.Writer(), map[string]string{
        "Title":   "Welcome",
        "Message": "Hello!",
    })
}
```

## Setting status codes

Each response method takes a status code as the first argument:

```go theme={null}
return c.JSON(201, createdUser)  // 201 Created
return c.Text(400, "bad input")  // 400 Bad Request
return c.JSON(500, errorBody)    // 500 Internal Server Error
```

If you pass `0`, Mizu uses the previously set status (default 200):

```go theme={null}
c.Status(202)
return c.Text(0, "Accepted")  // Uses status 202
```

Check the current status:

```go theme={null}
code := c.StatusCode()
```

## Working with headers

Set headers before writing the body:

```go theme={null}
func handler(c *mizu.Ctx) error {
    // Set a header
    c.Header().Set("Cache-Control", "max-age=3600")

    // Set only if not already present
    c.HeaderIfNone("X-Request-Id", "abc123")

    return c.JSON(200, data)
}
```

Once you write the body (via `c.JSON()`, `c.Text()`, etc.), headers are sent and can't be changed.

## Redirects

Send the client to a different URL:

```go theme={null}
func handler(c *mizu.Ctx) error {
    return c.Redirect(302, "/login")
}
```

| Code | Meaning            | When to use                                |
| ---- | ------------------ | ------------------------------------------ |
| 301  | Moved Permanently  | URL changed forever                        |
| 302  | Found              | Temporary redirect (default if you pass 0) |
| 303  | See Other          | Redirect after POST                        |
| 307  | Temporary Redirect | Preserve method                            |
| 308  | Permanent Redirect | Preserve method                            |

## Empty responses

Return no body with status 204:

```go theme={null}
func deleteUser(c *mizu.Ctx) error {
    // ... delete the user
    return c.NoContent()  // 204 No Content
}
```

## Serving files

Serve a file from disk:

```go theme={null}
func handler(c *mizu.Ctx) error {
    // File(statusCode, filePath)
    return c.File(200, "./public/logo.png")
}
```

Force the browser to download (adds Content-Disposition header):

```go theme={null}
func handler(c *mizu.Ctx) error {
    // Download(statusCode, filePath, downloadName)
    return c.Download(200, "./reports/data.csv", "report-2024.csv")
}
```

Both methods:

* Auto-detect Content-Type from the file extension
* Support range requests (for video seeking, resumable downloads)
* Handle If-Modified-Since caching

## Streaming responses

Send data gradually as it becomes available:

```go theme={null}
func handler(c *mizu.Ctx) error {
    return c.Stream(func(w io.Writer) error {
        for i := 0; i < 10; i++ {
            fmt.Fprintf(w, "chunk %d\n", i)
            time.Sleep(100 * time.Millisecond)
        }
        return nil
    })
}
```

## Server-Sent Events (SSE)

Send real-time updates to the client:

```go theme={null}
func events(c *mizu.Ctx) error {
    ch := make(chan any)

    // Send updates from a goroutine
    go func() {
        defer close(ch)  // Closing the channel ends the stream
        for i := 0; i < 10; i++ {
            ch <- map[string]int{"count": i}
            time.Sleep(time.Second)
        }
    }()

    return c.SSE(ch)
}
```

SSE sets these headers automatically:

* `Content-Type: text/event-stream`
* `Cache-Control: no-cache`
* `Connection: keep-alive`

Client-side JavaScript:

```javascript theme={null}
const events = new EventSource('/events');
events.onmessage = (e) => {
    const data = JSON.parse(e.data);
    console.log('Received:', data);
};
```

## Raw bytes

Send arbitrary bytes with a custom content type:

```go theme={null}
func handler(c *mizu.Ctx) error {
    data := []byte{0x00, 0x01, 0x02}
    return c.Bytes(200, data, "application/octet-stream")
}
```

## Method reference

| Method      | Signature                               | Purpose            |
| ----------- | --------------------------------------- | ------------------ |
| `Text`      | `(code int, s string) error`            | Plain text         |
| `JSON`      | `(code int, v any) error`               | JSON data          |
| `HTML`      | `(code int, s string) error`            | HTML content       |
| `File`      | `(code int, path string) error`         | Serve file         |
| `Download`  | `(code int, path, name string) error`   | Force download     |
| `Bytes`     | `(code int, b []byte, ct string) error` | Raw bytes          |
| `Stream`    | `(fn func(io.Writer) error) error`      | Streaming          |
| `SSE`       | `(ch <-chan any) error`                 | Server-Sent Events |
| `Redirect`  | `(code int, url string) error`          | Redirect           |
| `NoContent` | `() error`                              | 204 No Content     |

## Next steps

<CardGroup cols={2}>
  <Card title="Request" icon="arrow-down-to-line" href="/guides/concepts/request">
    Read input from requests.
  </Card>

  <Card title="Error Handling" icon="bug" href="/guides/concepts/error">
    Handle response errors.
  </Card>
</CardGroup>
