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

# Context

> The Context struct is the single object passed to every handler and middleware in Lightning. It exposes all request data and response helpers.

Every handler and middleware receives a `*lightning.Context`. It wraps the underlying HTTP request and response and provides a clean API for reading input, writing output, and sharing data across the middleware chain.

```go theme={null}
app.Get("/example", func(ctx *lightning.Context) {
    // ctx is your entire interface to the request and response
})
```

Two fields are always available directly:

```go theme={null}
ctx.Method  // e.g. "GET"
ctx.Path    // e.g. "/users/42"
```

***

## Reading request data

### URL parameters

URL parameters are the named segments defined in the route pattern (e.g. `:id`).

```go theme={null}
app.Get("/users/:id", func(ctx *lightning.Context) {
    id, err := ctx.ParamInt("id")
    if err != nil {
        ctx.JSONError(lightning.StatusBadRequest, "invalid id")
        return
    }
    ctx.JSON(lightning.StatusOK, lightning.Map{"id": id})
})
```

| Method                                          | Return type |
| ----------------------------------------------- | ----------- |
| `ctx.Param(key string) string`                  | `string`    |
| `ctx.ParamInt(key string) (int, error)`         | `int`       |
| `ctx.ParamInt64(key string) (int64, error)`     | `int64`     |
| `ctx.ParamUInt(key string) (uint, error)`       | `uint`      |
| `ctx.ParamUInt64(key string) (uint64, error)`   | `uint64`    |
| `ctx.ParamFloat32(key string) (float32, error)` | `float32`   |
| `ctx.ParamFloat64(key string) (float64, error)` | `float64`   |
| `ctx.Params() map[string]string`                | all params  |

### Query parameters

```go theme={null}
app.Get("/search", func(ctx *lightning.Context) {
    q := ctx.Query("q")                     // string
    page, _ := ctx.QueryInt("page")         // int, default 0 when absent
    active, _ := ctx.QueryBool("active")    // bool
    all := ctx.Queries()                    // map[string][]string
    _ = q; _ = page; _ = active; _ = all
    ctx.JSON(lightning.StatusOK, lightning.Map{"q": q, "page": page})
})
```

| Method                                          | Return type |
| ----------------------------------------------- | ----------- |
| `ctx.Query(key string) string`                  | `string`    |
| `ctx.QueryBool(key string) (bool, error)`       | `bool`      |
| `ctx.QueryInt(key string) (int, error)`         | `int`       |
| `ctx.QueryInt8(key string) (int8, error)`       | `int8`      |
| `ctx.QueryInt32(key string) (int32, error)`     | `int32`     |
| `ctx.QueryInt64(key string) (int64, error)`     | `int64`     |
| `ctx.QueryUInt(key string) (uint, error)`       | `uint`      |
| `ctx.QueryUInt8(key string) (uint8, error)`     | `uint8`     |
| `ctx.QueryUInt32(key string) (uint32, error)`   | `uint32`    |
| `ctx.QueryUInt64(key string) (uint64, error)`   | `uint64`    |
| `ctx.QueryFloat32(key string) (float32, error)` | `float32`   |
| `ctx.QueryFloat64(key string) (float64, error)` | `float64`   |
| `ctx.Queries() map[string][]string`             | all params  |

<Note>
  Query methods that parse a numeric type return `0` (not an error) when the key is absent from the URL.
</Note>

### Request body

```go theme={null}
app.Post("/users", func(ctx *lightning.Context) {
    // Raw bytes
    raw := ctx.RawBody()

    // As a string
    text := ctx.StringBody()

    // Decode JSON
    type CreateUserRequest struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }
    var req CreateUserRequest
    if err := ctx.JSONBody(&req); err != nil {
        ctx.JSONError(lightning.StatusBadRequest, "invalid body")
        return
    }

    _ = raw; _ = text
    ctx.JSON(lightning.StatusOK, lightning.Map{"name": req.Name})
})
```

Pass `true` as the second argument to `JSONBody` to also run struct validation (powered by `go-playground/validator`):

```go theme={null}
if err := ctx.JSONBody(&req, true); err != nil {
    ctx.JSONError(lightning.StatusBadRequest, err.Error())
    return
}
```

### Headers

```go theme={null}
app.Get("/info", func(ctx *lightning.Context) {
    contentType := ctx.ContentType()            // Content-Type header
    auth := ctx.Header("Authorization")         // any header by name
    all := ctx.Headers()                        // map[string]string
    _ = contentType; _ = auth; _ = all
})
```

### Cookies

```go theme={null}
app.Get("/profile", func(ctx *lightning.Context) {
    session := ctx.Cookie("session")    // string, empty if not set
    all := ctx.Cookies()                // map[string]string
    _ = session; _ = all
})
```

### Client metadata

```go theme={null}
app.Get("/meta", func(ctx *lightning.Context) {
    ua   := ctx.UserAgent()             // User-Agent string
    ref  := ctx.Referer()              // Referer header
    addr := ctx.RemoteAddr()           // client IP:port
    ct   := ctx.ContentType()          // Content-Type header
    ajax := ctx.IsAjax()               // true if X-Requested-With: XMLHttpRequest
    ws   := ctx.IsWebSocket()          // true if Upgrade: websocket
    langs := ctx.AcceptedLanguages()   // []string from Accept-Language

    _ = ua; _ = ref; _ = addr; _ = ct; _ = ajax; _ = ws; _ = langs
})
```

***

## Writing responses

### JSON

```go theme={null}
ctx.JSON(lightning.StatusOK, lightning.Map{"message": "hello"})
```

### Plain text

```go theme={null}
ctx.Text(lightning.StatusOK, "pong")
```

### HTML

Load templates once at startup with `app.LoadHTMLGlob`, then render by template name:

```go theme={null}
app.LoadHTMLGlob("templates/*.html")

app.Get("/home", func(ctx *lightning.Context) {
    ctx.HTML(lightning.StatusOK, "index.html", lightning.Map{
        "title": "Home",
    })
})
```

### XML

```go theme={null}
type User struct {
    XMLName xml.Name `xml:"user"`
    Name    string   `xml:"name"`
}

app.Get("/user.xml", func(ctx *lightning.Context) {
    ctx.XML(lightning.StatusOK, User{Name: "Alice"})
})
```

### File download

```go theme={null}
app.Get("/export", func(ctx *lightning.Context) {
    if err := ctx.File("/tmp/report.csv"); err != nil {
        ctx.JSONError(lightning.StatusInternalServerError, "file not found")
    }
})
```

### Redirect

```go theme={null}
ctx.Redirect(lightning.StatusFound, "/login")
```

### Error response

`JSONError` returns an HTTP error status code alongside a JSON body:

```go theme={null}
ctx.JSONError(lightning.StatusNotFound, "user not found")
// HTTP 404 {"code":404,"message":"user not found"}
```

### Success and Fail helpers

<Tip>
  Use `ctx.Success` and `ctx.Fail` to return a consistent envelope shape across your entire API without repeating the structure in every handler.
</Tip>

`Success` always returns HTTP 200 with `code: 0`:

```go theme={null}
ctx.Success(lightning.Map{"id": 1, "name": "Alice"})
// HTTP 200
// {"code":0,"message":"ok","data":{"id":1,"name":"Alice"}}
```

`Fail` always returns HTTP 200 with a non-zero application error code and a message:

```go theme={null}
ctx.Fail(9999, "network error")
// HTTP 200
// {"code":9999,"message":"network error"}
```

This pattern lets clients always check the HTTP status for transport errors and the `code` field for application errors.

***

## Per-request data store

`SetData`, `GetData`, and `DelData` let you attach arbitrary values to the current request context. This is useful for passing data from middleware to downstream handlers without mutating global state.

```go theme={null}
// In middleware: set the authenticated user
app.Use(func(ctx *lightning.Context) {
    token := ctx.Header("Authorization")
    if token != "" {
        ctx.SetData("userID", 42)
    }
    ctx.Next()
})

// In a route handler: read what the middleware set
app.Get("/profile", func(ctx *lightning.Context) {
    userID, ok := ctx.GetData("userID").(int)
    if !ok {
        ctx.JSONError(lightning.StatusUnauthorized, "not authenticated")
        return
    }
    ctx.JSON(lightning.StatusOK, lightning.Map{"userID": userID})
})
```

`GetData` returns `any`, so you need a type assertion. `DelData` removes a key:

```go theme={null}
ctx.DelData("userID")
```

Data is scoped to the single request — it is cleared when the request completes.
