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