github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/docs_src/src/guide/basics/responses.md (about) 1 --- 2 meta: 3 - name: "og:title" 4 content: "Responses - Goyave" 5 - name: "twitter:title" 6 content: "Responses - Goyave" 7 - name: "title" 8 content: "Responses - Goyave" 9 --- 10 11 # Responses 12 13 [[toc]] 14 15 ## Introduction 16 17 Handlers receive a `goyave.Response` and a `goyave.Request` as parameters. 18 19 `goyave.Response` implements `http.ResponseWriter`. This object brings a number of convenient methods to write HTTP responses. 20 21 If you didn't write anything before the request lifecycle ends, `204 No Content` is automatically written. 22 23 ## Reference 24 25 All functions below require the `goyave` package to be imported. 26 27 ``` go 28 import "github.com/System-Glitch/goyave/v2" 29 ``` 30 31 **List of response methods**: 32 ::: table 33 [GetStatus](#response-getstatus) 34 [GetError](#response-geterror) 35 [Header](#response-header) 36 [Status](#response-status) 37 [JSON](#response-json) 38 [String](#response-string) 39 [Write](#response-write) 40 [File](#response-file) 41 [Download](#response-download) 42 [Error](#response-error) 43 [Cookie](#response-cookie) 44 [Redirect](#response-redirect) 45 [TemporaryRedirect](#response-temporaryredirect) 46 [Render](#response-render) 47 [RenderHTML](#response-renderhtml) 48 [HandleDatabaseError](#response-handledatabaseerror) 49 ::: 50 51 #### Response.GetStatus 52 53 Returns the response code for this request or `0` if not yet set. 54 55 | Parameters | Return | 56 |------------|--------| 57 | | `int` | 58 59 **Example:** 60 ``` go 61 fmt.Println(response.GetStatus()) // 200 62 ``` 63 64 #### Response.GetError 65 66 Returns the value which caused a panic in the request's handling, or `nil`. The response error is also set when [`Error()`](#response-error) is called. 67 68 This method is mainly used in [status handlers](../advanced/status-handlers.html). 69 70 | Parameters | Return | 71 |------------|---------------| 72 | | `interface{}` | 73 74 **Example:** 75 ``` go 76 fmt.Println(response.GetError()) // "panic: something wrong happened" 77 ``` 78 79 #### Response.Header 80 81 Returns the Header map that will be sent. 82 83 | Parameters | Return | 84 |------------|---------------| 85 | | `http.Header` | 86 87 **Example:** 88 ``` go 89 header := response.Header() 90 header.Set("Content-Type", "application/json") 91 ``` 92 93 #### Response.Status 94 95 Write the given status code. Calling this method a second time will have no effect. 96 97 | Parameters | Return | 98 |--------------|--------| 99 | `status int` | `void` | 100 101 **Example:** 102 ``` go 103 response.Status(http.StatusOK) 104 ``` 105 106 #### Response.JSON 107 108 Write JSON data as a response. This method automatically sets the `Content-Type` header. 109 110 | Parameters | Return | 111 |--------------------|---------| 112 | `responseCode int` | `error` | 113 | `data interface{}` | | 114 115 **Example:** 116 ``` go 117 response.JSON(http.StatusOK, map[string]interface{}{ 118 "name": "John Doe", 119 "tags": []string{"tag1", "tag2"}, 120 }) 121 ``` 122 123 #### Response.String 124 125 Write a string as a response. 126 127 | Parameters | Return | 128 |--------------------|---------| 129 | `responseCode int` | `error` | 130 | `message string` | | 131 132 **Example:** 133 ``` go 134 response.String(http.StatusOK, "Hello there!") 135 ``` 136 137 #### Response.Write 138 139 Write the data as a response. Can be used to write in-memory files. This method can be called successively. 140 141 Returns the number of bytes written. 142 143 | Parameters | Return | 144 |---------------|---------| 145 | `data []byte` | `int` | 146 | | `error` | 147 148 **Example:** 149 ``` go 150 response.Write([]byte("Hello there!")) 151 ``` 152 153 #### Response.File 154 155 Write a file as an inline element. 156 157 Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status `404 Not Found`. The given path can be relative or absolute. 158 159 If you want the file to be sent as a download ("Content-Disposition: attachment"), use the `Download` function instead. 160 161 | Parameters | Return | 162 |---------------|---------| 163 | `file string` | `error` | 164 165 **Example:** 166 ``` go 167 response.File("/path/to/file") 168 ``` 169 170 #### Response.Download 171 172 Write a file as an attachment element. 173 174 Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status `404 Not Found`. The given path can be relative or absolute. 175 176 The `fileName` parameter defines the name the client will see. In other words, it sets the header "Content-Disposition" to "attachment; filename="${fileName}"" 177 178 If you want the file to be sent as an inline element ("Content-Disposition: inline"), use the `File` function instead. 179 180 | Parameters | Return | 181 |-------------------|---------| 182 | `file string` | `error` | 183 | `fileName string` | | 184 185 **Example:** 186 ``` go 187 response.Download("/path/to/file", "awesome.txt") 188 ``` 189 190 #### Response.Error 191 192 Print the error in the console and return it with an error code `500`. 193 194 If debugging is enabled in the config, the error is also written in the response using the JSON format, and the stacktrace is printed in the console. If debugging is not enabled, only the stauts code is set, which means you can still write to the response, or use your error [status handler](../advanced/status-handlers.html). 195 196 | Parameters | Return | 197 |-------------------|---------| 198 | `err interface{}` | `error` | 199 200 **Example:** 201 ``` go 202 v, err := strconv.Atoi("-42") 203 response.Error(err) 204 ``` 205 206 #### Response.Cookie 207 208 Add a Set-Cookie header to the response. The provided cookie must have a valid Name. Invalid cookies may be silently dropped. 209 210 | Parameters | Return | 211 |------------------------|--------| 212 | `cookie *http.Cookie*` | `void` | 213 214 **Example:** 215 ``` go 216 cookie := &http.Cookie{ 217 Name: "cookie-name", 218 Value: "value", 219 } 220 response.Cookie(cookie) 221 ``` 222 223 ::: warning 224 Protect yourself from [CSRF attacks](https://en.wikipedia.org/wiki/Cross-site_request_forgery) when using cookies! 225 ::: 226 227 #### Response.Redirect 228 229 Send a permanent redirect response. (HTTP 308) 230 231 | Parameters | Return | 232 |--------------|--------| 233 | `url string` | `void` | 234 235 **Example:** 236 ``` go 237 response.Redirect("/login") 238 ``` 239 240 #### Response.TemporaryRedirect 241 242 Send a temporary redirect response. (HTTP 307) 243 244 | Parameters | Return | 245 |--------------|--------| 246 | `url string` | `void` | 247 248 **Example:** 249 ``` go 250 response.TemporaryRedirect("/maintenance") 251 ``` 252 253 #### Response.Render 254 255 Render a text template with the given data. This method uses the [Go's template API](https://golang.org/pkg/text/template/). 256 257 The template path is relative to the `resources/template` directory. 258 259 | Parameters | Return | 260 |-----------------------|---------| 261 | `responseCode int` | `error` | 262 | `templatePath string` | | 263 | `data interface{}` | | 264 265 **Example:** 266 ``` go 267 type Inventory struct { 268 Material string 269 Count uint 270 } 271 272 sweaters := Inventory{"wool", 17} 273 274 // data can also be a map[string]interface{} 275 // Here, "resources/template/template.txt" will be used. 276 if err := response.Render(http.StatusOK, "template.txt", sweaters); err != nil { 277 response.Error(err) 278 } 279 ``` 280 281 #### Response.RenderHTML 282 283 Render an HTML template with the given data. This method uses the [Go's template API](https://golang.org/pkg/html/template/). 284 285 The template path is relative to the `resources/template` directory. 286 287 | Parameters | Return | 288 |-----------------------|---------| 289 | `responseCode int` | `error` | 290 | `templatePath string` | | 291 | `data interface{}` | | 292 293 **Example:** 294 ``` go 295 type Inventory struct { 296 Material string 297 Count uint 298 } 299 300 sweaters := Inventory{"wool", 17} 301 302 // data can also be a map[string]interface{} 303 // Here, "resources/template/inventory.html" will be used. 304 if err := response.RenderHTML(http.StatusOK, "inventory.html", sweaters); err != nil { 305 response.Error(err) 306 } 307 ``` 308 309 #### Response.HandleDatabaseError 310 311 Takes a database query result and checks if any error has occurred. 312 313 Automatically writes HTTP status code 404 Not Found if the error is a "Not found" error. Calls `Response.Error()` if there is another type of error. 314 315 Returns `true` if there is no error. 316 317 | Parameters | Return | 318 |---------------|--------| 319 | `db *gorm.DB` | `bool` | 320 321 **Example:** 322 ``` go 323 product := model.Product{} 324 result := database.GetConnection().First(&product, id) 325 if response.HandleDatabaseError(result) { 326 response.JSON(http.StatusOK, product) 327 } 328 ``` 329 330 ## Chained writers 331 332 <p><Badge text="Since v2.7.0"/></p> 333 334 It is possible to replace the `io.Writer` used by the `Response` object. This allows for more flexibility when manipulating the data you send to the client. It makes it easier to compress your response, write it to logs, etc. You can chain as many writers as you want. The writer replacement is most often done in a middleware. If your writer implements `io.Closer`, it will be automatically closed at the end of the request's lifecycle. 335 336 The following example is a simple implementation of a middleware logging everything sent by the server to the client. 337 ``` go 338 import ( 339 "io" 340 "log" 341 342 "github.com/System-Glitch/goyave/v2" 343 ) 344 345 type LogWriter struct { 346 writer io.Writer 347 response *goyave.Response 348 body []byte 349 } 350 351 func (w *LogWriter) Write(b []byte) (int, error) { 352 w.body = append(w.body, b...) 353 return w.writer.Write(b) 354 } 355 356 func (w *LogWriter) Close() error { 357 // The chained writer MUST be closed if it's closeable. 358 // Therefore, all chained writers should implement io.Closer. 359 360 goyave.Logger.Println("RESPONSE", w.response.GetStatus(), string(w.body)) 361 362 if wr, ok := w.writer.(io.Closer); ok { 363 return wr.Close() 364 } 365 return nil 366 } 367 368 func LogMiddleware(next goyave.Handler) goyave.Handler { 369 return func(response *goyave.Response, request *goyave.Request) { 370 logWriter := &LogWriter{ 371 writer: response.Writer(), 372 response: response, 373 } 374 response.SetWriter(logWriter) 375 376 next(response, request) 377 } 378 } 379 ``` 380 381 #### Response.Writer 382 383 Return the current writer used to write the response. 384 385 Note that the returned writer is not necessarily a `http.ResponseWriter`, as it can be replaced using `SetWriter`. 386 387 | Parameters | Return | 388 |------------|-------------| 389 | | `io.Writer` | 390 391 #### Response.SetWriter 392 393 Set the writer used to write the response. 394 395 This can be used to chain writers, for example to enable gzip compression, or for logging. The original `http.ResponseWriter` is always kept. 396 397 | Parameters | Return | 398 |--------------------|--------| 399 | `writer io.Writer` | |