github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/docs_src/src/guide/basics/routing.md (about) 1 --- 2 meta: 3 - name: "og:title" 4 content: "Routing - Goyave" 5 - name: "twitter:title" 6 content: "Routing - Goyave" 7 - name: "title" 8 content: "Routing - Goyave" 9 --- 10 11 # Routing 12 13 [[toc]] 14 15 ## Introduction 16 17 Routing is an essential part of any Goyave application. Routes definition is the action of associating a URI, sometimes having parameters, with a handler which will process the request and respond to it. Separating and naming routes clearly is important to make your API or website clear and expressive. 18 19 All features below require the `goyave` package to be imported. 20 21 ``` go 22 import "github.com/System-Glitch/goyave/v2" 23 ``` 24 25 Routes are defined in **routes registrer functions**. The main route registrer is passed to `goyave.Start()` and is executed automatically with a newly created root-level **router**. 26 27 ``` go 28 func Register(router *goyave.Router) { 29 // Register your routes here 30 } 31 ``` 32 33 ## Basic routing 34 35 Although it's not recommended, routes can be defined using **closures**. This is a very simple way of defining routes that can be used for scaffolding or quick testing. 36 37 ``` go 38 router.Route("GET", "/hello", func(response *goyave.Response, r *goyave.Request) { 39 response.String(http.StatusOK, "Hi!") 40 }) 41 ``` 42 43 #### Router.Route 44 45 Register a new route. 46 Multiple methods can be passed using a pipe-separated string. 47 48 If the router has CORS options set, the `OPTIONS` method is automatically added to the matcher if it's missing, so it allows pre-flight requests. 49 50 Returns the generated route. 51 52 | Parameters | Return | 53 |--------------------------|-----------------| 54 | `methods string` | `*goyave.Route` | 55 | `uri string` | | 56 | `handler goyave.Handler` | | 57 58 **Examples:** 59 ``` go 60 router.Route("GET", "/hello", myHandlerFunction) 61 router.Route("POST", "/user", user.Register) 62 router.Route("PUT|PATCH", "/user", user.Update) 63 router.Route("POST", "/product", product.Store) 64 ``` 65 66 ::: tip 67 `goyave.Handler` is an alias for `func(*goyave.Response, *goyave.Request)`. 68 ::: 69 70 You can also register routes by using the `Get`, `Post`, `Put`, `Patch`, `Delete` and `Options` methods: 71 ``` go 72 router.Get("/hello", myHandlerFunction) 73 router.Post("/user", user.Register) 74 router.Put("/product/{id:[0-9]+}", product.Update) 75 router.Patch("/product/{id:[0-9]+}", product.Update) 76 router.Delete("/product/{id:[0-9]+}", product.Destroy) 77 router.Options("/options", myHandlerFunction) 78 ``` 79 80 | Parameters | Return | 81 |--------------------------|-----------------| 82 | `uri string` | `*goyave.Route` | 83 | `handler goyave.Handler` | | 84 85 ## Route reference 86 87 <p><Badge text="Since v2.6.0"/></p> 88 89 ::: table 90 [Name](#route-name) 91 [GetName](#route-getname) 92 [BuildURL](#route-buildurl) 93 [GetURI](#route-geturi) 94 [GetFullURI](#route-getfulluri) 95 [GetMethods](#route-getmethods) 96 [Validate](#route-validate) 97 [Middleware](#route-middleware) 98 ::: 99 100 #### Route.Name 101 102 Set the name of this route. 103 104 Panics if a route with the same name already exists. 105 106 Returns itself. 107 108 | Parameters | Return | 109 |---------------|-----------------| 110 | `name string` | `*goyave.Route` | 111 112 **Examples:** 113 ``` go 114 router.Route("GET", "/product/{id:[0-9]+}", myHandlerFunction).Name("product.show") 115 ``` 116 117 #### Route.GetName 118 119 Get the name of this route. 120 121 | Parameters | Return | 122 |------------|----------| 123 | | `string` | 124 125 **Examples:** 126 ``` go 127 fmt.Println(route.GetName()) // "product-create" 128 ``` 129 130 #### Route.BuildURL 131 132 Build a full URL pointing to this route. 133 134 Panics if the amount of parameters doesn't match the amount of actual parameters for this route. 135 136 | Parameters | Return | 137 |------------------------|----------| 138 | `parameters ...string` | `string` | 139 140 **Examples:** 141 ``` go 142 fmt.Println(route.BuildURL("42")) // "http://localhost:8080/product/42" 143 ``` 144 145 #### Route.GetURI 146 147 Get the URI of this route. 148 149 The returned URI is relative to the parent router of this route, it is NOT the full path to this route. 150 151 Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client. 152 153 | Parameters | Return | 154 |------------|----------| 155 | | `string` | 156 157 **Examples:** 158 ``` go 159 fmt.Println(route.GetURI()) // "/{id:[0-9]+}" 160 ``` 161 162 #### Route.GetFullURI 163 164 Get the URI of this route. 165 166 Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client. 167 168 | Parameters | Return | 169 |------------|----------| 170 | | `string` | 171 172 **Examples:** 173 ``` go 174 fmt.Println(route.GetFullURI()) // "/product/{id:[0-9]+}" 175 ``` 176 177 #### Route.GetMethods 178 179 Returns the methods the route matches against. 180 181 | Parameters | Return | 182 |------------|------------| 183 | | `[]string` | 184 185 **Examples:** 186 ``` go 187 fmt.Println(route.GetMethods()) // [GET OPTIONS] 188 ``` 189 190 #### Route.Validate 191 192 <p><Badge text="Since v3.0.0"/></p> 193 194 Validate adds validation rules to this route. If the user-submitted data doesn't pass validation, the user will receive an error and messages explaining what is wrong. 195 196 Returns itself. 197 198 | Parameters | Return | 199 |------------------------------------|-----------------| 200 | `validationRules validation.Ruler` | `*goyave.Route` | 201 202 **Examples:** 203 ``` go 204 router.Post("/user", user.Register).Validate(user.RegisterRequest) 205 ``` 206 207 ::: tip 208 Learn more about validation and rules sets [here](./validation.html). 209 ::: 210 211 #### Route.Middleware 212 213 <p><Badge text="Since v3.0.0"/></p> 214 215 Register middleware for this route only. 216 217 Returns itself. 218 219 | Parameters | Return | 220 |-----------------------------------|-----------------| 221 | `middleware ...goyave.Middleware` | `*goyave.Route` | 222 223 **Examples:** 224 ``` go 225 router.Put("/product", product.Update).Middleware(middleware.Admin) 226 ``` 227 228 ::: tip 229 Learn more about middleware [here](./middleware.html). 230 ::: 231 232 ## Route parameters 233 234 URIs can have parameters, defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. 235 236 **Example:** 237 ``` go 238 router.Get("/product/{key}", product.Show) 239 router.Get("/product/{id:[0-9]+}", product.ShowById) 240 router.Get("/category/{category}/{id:[0-9]+}", category.Show) 241 ``` 242 243 Regex groups can be used inside patterns, as long as they are non-capturing (`(?:re)`). For example: 244 ``` go 245 router.Get("/category/{category}/{sort:(?:asc|desc|new)}", category.ShowSorted) 246 ``` 247 248 Route parameters can be retrieved as a `map[string]string` in handlers using the request's `Params` attribute. 249 ``` go 250 func myHandlerFunction(response *goyave.Response, request *goyave.Request) { 251 category := request.Params["category"] 252 id, _ := strconv.Atoi(request.Params["id"]) 253 //... 254 } 255 ``` 256 257 ## Named routes 258 259 <p><Badge text="Since v2.6.0"/></p> 260 261 It is possible to give a name to your routes to make it easier to retrieve them later and build dynamic URLs. 262 263 ``` go 264 router.Route("GET", "/product/{id:[0-9]+}", myHandlerFunction).Name("product.show") 265 ``` 266 267 The route can now be retrieved from any router or from the global helper: 268 269 ``` go 270 route := router.GetRoute("product.show") 271 // or 272 route := goyave.GetRoute("product.show") 273 274 fmt.Println(route.BuildURL("42")) // "http://localhost:8080/product/42" 275 ``` 276 277 #### goyave.GetRoute 278 279 Get a named route. Returns nil if the route doesn't exist. 280 281 | Parameters | Return | 282 |---------------|-----------------| 283 | `name string` | `*goyave.Route` | 284 285 ## Validation 286 287 You can assign a validation rules set to each route. Learn more in the dedicated [section](./validation.html). You should always validate incoming requests. 288 289 ``` go 290 router.Route("POST", "/product", product.Store).Validate(validation.RuleSet{ 291 "Name": {"required", "string", "min:4"}, 292 "Price": {"required", "numeric"}, 293 }) 294 ``` 295 296 ::: tip 297 It's not recommended to define rules set directly in the route definition. You should define rules sets in your controller package. 298 ::: 299 300 ## Middleware 301 302 Middleware are handlers executed before the controller handler. Learn more in the dedicated [section](./middleware.html). 303 304 Middleware are applied to a router or a sub-router **before the routes definition**. Therefore, all routes in that router and its sub-routers will execute them before executing their associated handler. 305 306 To assign a middleware to a router, use the `router.Middleware()` function. Many middleware can be assigned at once. The assignment order is important as middleware will be **executed in order**. 307 308 #### Router.Middleware 309 310 Middleware apply one or more middleware to the route group. 311 312 | Parameters | Return | 313 |-----------------------------------|--------| 314 | `middleware ...goyave.Middleware` | `void` | 315 316 **Example:** 317 ``` go 318 router.Middleware(middleware.DisallowNonValidatedFields) 319 ``` 320 321 --- 322 323 Middleware can also be applied to specific routes. You can add as many as you want. 324 325 **Example:** 326 ``` go 327 router.Route("POST", "/product", product.Store).Validate(product.StoreRequest).Middleware(middleware.Trim) 328 ``` 329 330 ## Groups and sub-routers 331 332 Grouping routes makes it easier to define multiple routes having the same prefix and/or middleware. 333 334 Let's take a simple scenario where we want to implement a user CRUD. All our routes will start with `/user`, so we are going to create a sub-router for it: 335 ``` go 336 userRouter := router.Subrouter("/user") 337 ``` 338 339 In our application, user profiles are public: anyone can see the user profiles without being authenticated. However, only authenticated users can modify their information and delete their account. We don't want to add some redundancy and apply the authentication middleware for each route needing it, so we are going to create another sub-router. Sub-routers having an empty prefix are called **route groups**. 340 ```go 341 userRouter.Route("GET", "/{username}", user.Show) 342 userRouter.Route("POST", "", user.Register).Validate(user.RegisterRequest) 343 344 authUserRouter := userRouter.Subrouter("") // Don't add a prefix 345 authUserRouter.Middleware(authenticationMiddleware) 346 authUserRouter.Route("PUT", "/{id}", user.Update).Validate(user.UpdateRequest) 347 authUserRouter.Route("DELETE", "/{id}", user.Delete) 348 ``` 349 350 To improve your routes definition readability, you should create a new route registrer for each feature. In our example, our definitions would look like this: 351 ``` go 352 func registerUserRoutes(router *goyave.Router) { 353 //... 354 } 355 356 // Register is the main route registrer. 357 func Register(router *goyave.Router) { 358 registerUserRoutes(router) 359 registerProductRoutes(router) 360 //... 361 } 362 ``` 363 364 Sub-routers are checked before routes, meaning that they have priority over the latter. If you have a router sharing a prefix with a higher-level level route, **it will never match** because the sub-router will match first. 365 ``` go 366 subrouter := router.Subrouter("/product") 367 subrouter.Route("GET", "/{id:[0-9]+}", handler) 368 369 router.Route("GET", "/product/{id:[0-9]+}", handler) // This route will never match 370 router.Route("GET", "/product/category", handler) // This one neither 371 ``` 372 373 ## Serve static resources 374 375 The Goyave router provides a way to serve a directory of static resources, including its sub-directories. 376 377 Let's say you have the following directory structure: 378 379 :::vue 380 . 381 └── static 382 ├── js 383 │ └── index.js 384 ├── img 385 │ ├── favicon.ico 386 │ └── logo.png 387 ├── css 388 │ └── styles.css 389 └── index.html 390 ::: 391 392 If you want to serve the `static` directory, register the following route: 393 394 ``` go 395 router.Static("/", "static", false) 396 ``` 397 398 If a user requests `http://yourdomain.com/js/index.js`, the corresponding file will be sent as a response. 399 400 If no file is given (`http://yourdomain.com/`), or if the request URI is a directory (`http://yourdomain.com/img`), Goyave will look for a `index.html` file and send it if it exists. An error 404 Not Found is otherwise returned. 401 402 ::: tip 403 This method is especially useful to serve Single Page Applications from your API. (Angular, Vue.js, React applications) 404 ::: 405 406 #### Router.Static 407 408 Static serve a directory and its sub-directories of static resources. 409 Set the `download` parameter to true if you want the files to be sent as an attachment instead of an inline element. 410 411 The `directory` parameter can be a relative or an absolute path. 412 413 | Parameters | Return | 414 |-----------------------------------|--------| 415 | `uri string` | `void` | 416 | `directory string` | | 417 | `download bool` | | 418 | `middleware ...goyave.Middleware` | | 419 420 **Example:** 421 ``` go 422 router.Static("/public", "/path/to/static/dir", false) 423 ``` 424 425 ## Native handlers 426 427 <p><Badge text="Since v2.0.0"/></p> 428 429 #### goyave.NativeHandler 430 431 NativeHandler is an adapter function for `http.Handler`. With this adapter, you can plug non-Goyave handlers to your application. 432 433 Just remember that the body contains the raw data, which haven't been validated nor converted. This means that **native handlers are not guaranteed to work** and cannot modify the request data. Request properties, such as headers, can still be modified. 434 435 The actual response writer passed to the native handler is a `goyave.Response`. 436 437 ::: warning 438 This feature is a compatibility layer with the rest of the Golang web ecosystem. Prefer using Goyave handlers if possible. 439 ::: 440 441 442 | Parameters | Return | 443 |------------------------|------------------| 444 | `handler http.Handler` | `goyave.Handler` | 445 446 **Example:** 447 ``` go 448 httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 449 w.Write([]byte("Hello world")) 450 }) 451 router.Route("GET", "/user", goyave.NativeHandler(httpHandler)) 452 ``` 453 454 #### goyave.NativeMiddleware 455 456 `NativeMiddleware` is an adapter function for standard library middleware. 457 458 Native middleware work like native handlers. See [`NativeHandler`](#goyave-nativehandler) for more details. 459 460 | Parameters | Return | 461 |------------------------------------------|---------------------| 462 | `middleware goyave.NativeMiddlewareFunc` | `goyave.Middelware` | 463 464 ::: tip 465 `goyave.NativeMiddlewareFunc` is defined as follows: 466 467 ``` go 468 // NativeMiddlewareFunc is a function which receives an http.Handler and returns another http.Handler. 469 type NativeMiddlewareFunc func(http.Handler) http.Handler 470 ``` 471 ::: 472 473 **Example:** 474 ``` go 475 middleware := goyave.NativeMiddleware(func(next http.Handler) http.Handler { 476 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 477 w.Write([]byte("Hello world")) 478 next.ServeHTTP(w, r) // Don't call "next" if your middleware is blocking. 479 }) 480 }) 481 router.Middleware(middleware) 482 ``` 483 484