> For the complete documentation index, see [llms.txt](https://gocopper.gitbook.io/copper/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gocopper.gitbook.io/copper/http/read-and-write-json.md).

# Read & Write JSON

Copper provides `chttp.JSONReaderWriter` that can be used to read, validate, and respond in JSON format. `chttp.JSONReaderWriter` is available by default on Routers generated by the Copper CLI.

### Read JSON

In the example below, JSON is read from the request body into the `body` variable using the `ReadJSON` method. On failure, it writes an appropriate status code & response to the response body and returns `false`.

```go
func (ro *Router) HandleRocketLaunch(w http.ResponseWriter, r *http.Request) {
    var body struct {
        RocketID string `json:"rocket_id"`
    }
    
    if ok := ro.rw.ReadJSON(w, r, &body); !ok {
        return
    }
    
    // Handle request with body..
}
```

### Validate Request Body

The `ReadJSON` method integrates with `asaskevich/govalidator` to validate the request body. If the validation fails, the method responds with `400 Bad Request` status code.

```go
var body struct {
    RocketID string `json:"rocket_id" valid:"required`
}
```

### Write JSON

The `WriteJSON` method handles marshaling, error checking, and setting the `Content-Type: application/json` header.

Below is a full example of reading a validated request body, calling the business logic layer, handling errors, and finally writing an HTTP response.

```go
func (ro *Router) HandleRocketLaunch(w http.ResponseWriter, r *http.Request) {    
    var body struct {
        RocketID string `json:"rocket_id" valid:"required"`
    }
    
    if ok := ro.rw.ReadJSON(w, r, &body); !ok {
        return
    }
    
    launchID, err := ro.rockets.Launch(r.Context(), body.RocketID)
    if err != nil {
        ro.logger.Error("Failed to launch rocket", err)
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    ro.rw.WriteJSON(w, chttp.WriteJSONParams{
        StatusCode: http.StatusCreated,
        Data: map[string]string{
            "launch_id": launchID,
        },
    })
}
```
