goyave.dev/goyave/v4@v4.4.11/README.md (about)

     1  <p align="center">
     2      <img src="https://raw.githubusercontent.com/go-goyave/goyave/master/resources/img/logo/goyave_text.png#gh-light-mode-only" alt="Goyave Logo" width="550"/>
     3      <img src="https://raw.githubusercontent.com/go-goyave/goyave/master/resources/img/logo/goyave_text_dark.png#gh-dark-mode-only" alt="Goyave Logo" width="550"/>
     4  </p>
     5  
     6  <p align="center">
     7      <a href="https://github.com/go-goyave/goyave/releases"><img src="https://img.shields.io/github/v/release/go-goyave/goyave?include_prereleases" alt="Version"/></a>
     8      <a href="https://github.com/go-goyave/goyave/actions"><img src="https://github.com/go-goyave/goyave/workflows/CI/badge.svg?branch=develop" alt="Build Status"/></a>
     9      <a href="https://coveralls.io/github/go-goyave/goyave?branch=master"><img src="https://coveralls.io/repos/github/go-goyave/goyave/badge.svg" alt="Coverage Status"/></a>
    10      <a href="https://goreportcard.com/report/goyave.dev/goyave"><img src="https://goreportcard.com/badge/goyave.dev/goyave" alt="Go Report"/></a>
    11  </p>
    12  
    13  <p align="center">
    14      <a href="https://github.com/go-goyave/goyave/blob/master/LICENSE"><img src="https://img.shields.io/dub/l/vibe-d.svg" alt="License"/></a>
    15      <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Awesome"/></a>
    16      <a href="https://discord.gg/mfemDMc"><img src="https://img.shields.io/discord/744264895209537617?logo=discord" alt="Discord"/></a>
    17  </p>
    18  
    19  <h2 align="center">An Elegant Golang Web Framework</h2>
    20  
    21  Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend development easy and enjoyable. It has a philosophy of cleanliness and conciseness to make programs more elegant, easier to maintain and more focused. Goyave is an **opinionated** framework, helping your applications keeping a uniform architecture and limit redundancy. With Goyave, expect a full package with minimum setup.
    22  
    23  - **Clean Code**: Goyave has an expressive, elegant syntax, a robust structure and conventions. Minimalist calls and reduced redundancy are among the Goyave's core principles.
    24  - **Fast Development**: Develop faster and concentrate on the business logic of your application thanks to the many helpers and built-in functions.
    25  - **Powerful functionalities**: Goyave is accessible, yet powerful. The framework includes routing, request parsing, validation, localization, testing, authentication, and more!
    26  - **Reliability**: Error reporting is made easy thanks to advanced error handling and panic recovery. The framework is deeply tested.
    27  
    28  ## Table of contents
    29  
    30  - [Learning Goyave](#learning-goyave)
    31  - [Getting started](#getting-started)
    32  - [Features tour](#features-tour)
    33  - [Contributing](#contributing)
    34  - [License](#license)
    35  
    36  ## Learning Goyave
    37  
    38  The Goyave framework has an extensive documentation covering in-depth subjects and teaching you how to run a project using Goyave from setup to deployment.
    39  
    40  - [Read the documentation](https://goyave.dev/guide/installation.html)
    41  - [pkg.go.dev](https://pkg.go.dev/goyave.dev/goyave/v4)
    42  - [Example project](https://github.com/go-goyave/goyave-blog-example)
    43  
    44  ## Getting started
    45  
    46  ### Requirements
    47  
    48  - Go 1.18+
    49  
    50  ### Install using the template project
    51  
    52  You can bootstrap your project using the [Goyave template project](https://github.com/go-goyave/goyave-template). This project has a complete directory structure already set up for you.
    53  
    54  #### Linux / MacOS
    55  
    56  ```
    57  $ curl https://goyave.dev/install.sh | bash -s github.com/username/projectname
    58  ```
    59  
    60  #### Windows (Powershell)
    61  
    62  ```
    63  > & ([scriptblock]::Create((curl "https://goyave.dev/install.ps1").Content)) -moduleName github.com/username/projectname
    64  ```
    65  
    66  ---
    67  
    68  Run `go run .` in your project's directory to start the server, then try to request the `hello` route.
    69  ```
    70  $ curl http://localhost:8080/hello
    71  Hi!
    72  ```
    73  
    74  There is also an `echo` route, with basic validation of the request body.
    75  ```
    76  $ curl -H "Content-Type: application/json" -X POST -d '{"text":"abc 123"}' http://localhost:8080/echo
    77  abc 123
    78  ```
    79  
    80  ## Features tour
    81  
    82  This section's goal is to give a **brief** look at the main features of the framework. It doesn't describe everything the framework has to offer, so don't consider this documentation. If you want a complete reference and documentation, head to [pkg.go.dev](https://pkg.go.dev/goyave.dev/goyave/v4) and the [official documentation](https://goyave.dev/guide/).
    83  
    84  - [Hello world from scratch](#hello-world-from-scratch)
    85  - [Configuration](#configuration)
    86  - [Routing](#routing)
    87  - [Controller](#controller)
    88  - [Middleware](#middleware)
    89  - [Validation](#validation)
    90  - [Database](#database)
    91  - [Localization](#localization)
    92  - [Testing](#testing)
    93  - [Status handlers](#status-handlers)
    94  - [CORS](#cors)
    95  - [Authentication](#authentication)
    96  - [Rate limiting](#rate-limiting)
    97  - [Websocket](#websocket)
    98  
    99  ### Hello world from scratch
   100  
   101  The example below shows a basic `Hello world` application using Goyave.
   102  
   103  ``` go
   104  import "goyave.dev/goyave/v4"
   105  
   106  func registerRoutes(router *goyave.Router) {
   107      router.Get("/hello", func(response *goyave.Response, request *goyave.Request) {
   108          response.String(http.StatusOK, "Hello world!")
   109      })
   110  }
   111  
   112  func main() {
   113      if err := goyave.Start(registerRoutes); err != nil {
   114          os.Exit(err.(*goyave.Error).ExitCode)
   115      }
   116  }
   117  ```
   118  
   119  ### Configuration
   120  
   121  To configure your application, use the `config.json` file at your project's root. If you are using the template project, copy `config.example.json` to `config.json`. The following code is an example of configuration for a local development environment:
   122  
   123  ```json
   124  {
   125      "app": {
   126          "name": "goyave_template",
   127          "environment": "localhost",
   128          "debug": true,
   129          "defaultLanguage": "en-US"
   130      },
   131      "server": {
   132          "host": "127.0.0.1",
   133          "maintenance": false,
   134          "protocol": "http",
   135          "domain": "",
   136          "port": 8080,
   137          "httpsPort": 8081,
   138          "timeout": 10,
   139          "maxUploadSize": 10
   140      },
   141      "database": {
   142          "connection": "mysql",
   143          "host": "127.0.0.1",
   144          "port": 3306,
   145          "name": "goyave",
   146          "username": "root",
   147          "password": "root",
   148          "options": "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local",
   149          "maxOpenConnections": 20,
   150          "maxIdleConnections": 20,
   151          "maxLifetime": 300,
   152          "autoMigrate": false
   153      }
   154  }
   155  ```
   156  
   157  If this config file misses some config entries, the default values will be used. 
   158  
   159  All entries are **validated**. That means that the application will not start if you provided an invalid value in your config (for example if the specified port is not a number). That also means that a goroutine trying to change a config entry with the incorrect type will panic.  
   160  Entries can be registered with a default value, their type and authorized values from any package. 
   161  
   162  **Getting a value:**
   163  ```go
   164  config.GetString("app.name") // "goyave"
   165  config.GetBool("app.debug") // true
   166  config.GetInt("server.port") // 80
   167  config.Has("app.name") // true
   168  ```
   169  
   170  **Setting a value:**
   171  ```go
   172  config.Set("app.name", "my awesome app")
   173  ```
   174  
   175  **Using environment variables:**
   176  ```json
   177  {
   178    "database": {
   179      "host": "${DB_HOST}"
   180    }
   181  }
   182  ```
   183  
   184  **Learn more about configuration in the [documentation](https://goyave.dev/guide/configuration.html).**
   185  
   186  ### Routing
   187  
   188  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.
   189  
   190  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**.
   191  
   192  ``` go
   193  func Register(router *goyave.Router) {
   194      // Register your routes here
   195  
   196      // With closure, not recommended
   197      router.Get("/hello", func(response *goyave.Response, r *goyave.Request) {
   198          response.String(http.StatusOK, "Hi!")
   199      })
   200  
   201      router.Get("/hello", myHandlerFunction)
   202      router.Post("/user", user.Register).Validate(user.RegisterRequest)
   203      router.Route("PUT|PATCH", "/user", user.Update).Validate(user.UpdateRequest)
   204      router.Route("POST", "/product", product.Store).Validate(product.StoreRequest).Middleware(middleware.Trim)
   205  }
   206  ```
   207  
   208  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. 
   209  
   210  **Example:**
   211  ``` go
   212  router.Get("/product/{key}", product.Show)
   213  router.Get("/product/{id:[0-9]+}", product.ShowById)
   214  router.Get("/category/{category}/{id:[0-9]+}", category.Show)
   215  ```
   216  
   217  Route parameters can be retrieved as a `map[string]string` in handlers using the request's `Params` attribute.
   218  ``` go
   219  func myHandlerFunction(response *goyave.Response, request *goyave.Request) {
   220      category := request.Params["category"]
   221      id, _ := strconv.Atoi(request.Params["id"])
   222      //...
   223  }
   224  ```
   225  
   226  **Learn more about routing in the [documentation](https://goyave.dev/guide/basics/routing.html).**
   227  
   228  ### Controller
   229  
   230  Controllers are files containing a collection of Handlers related to a specific feature. Each feature should have its own package. For example, if you have a controller handling user registration, user profiles, etc, you should create a `http/controller/user` package. Creating a package for each feature has the advantage of cleaning up route definitions a lot and helps keeping a clean structure for your project.
   231  
   232  A `Handler` is a `func(*goyave.Response, *goyave.Request)`. The first parameter lets you write a response, and the second contains all the information extracted from the raw incoming request.
   233  
   234  Handlers receive a `goyave.Response` and a `goyave.Request` as parameters.  
   235  `goyave.Request` can give you a lot of information about the incoming request, such as its headers, cookies, or body. Learn more [here](https://goyave.dev/guide/basics/requests.html).  
   236  `goyave.Response` implements `http.ResponseWriter` and is used to write a response. If you didn't write anything before the request lifecycle ends, `204 No Content` is automatically written. Learn everything about reponses [here](https://goyave.dev/guide/basics/responses.html).
   237  
   238  Let's take a very simple CRUD as an example for a controller definition:
   239  **http/controller/product/product.go**:
   240  ``` go
   241  func Index(response *goyave.Response, request *goyave.Request) {
   242      products := []model.Product{}
   243      result := database.Conn().Find(&products)
   244      if response.HandleDatabaseError(result) {
   245          response.JSON(http.StatusOK, products)
   246      }
   247  }
   248  
   249  func Show(response *goyave.Response, request *goyave.Request) {
   250      product := model.Product{}
   251      result := database.Conn().First(&product, request.Params["id"])
   252      if response.HandleDatabaseError(result) {
   253          response.JSON(http.StatusOK, product)
   254      }
   255  }
   256  
   257  func Store(response *goyave.Response, request *goyave.Request) {
   258      product := model.Product{
   259          Name:  request.String("name"),
   260          Price: request.Numeric("price"),
   261      }
   262      if err := database.Conn().Create(&product).Error; err != nil {
   263          response.Error(err)
   264      } else {
   265          response.JSON(http.StatusCreated, map[string]uint{"id": product.ID})
   266      }
   267  }
   268  
   269  func Update(response *goyave.Response, request *goyave.Request) {
   270      product := model.Product{}
   271      db := database.Conn()
   272      result := db.Select("id").First(&product, request.Params["id"])
   273      if response.HandleDatabaseError(result) {
   274          if err := db.Model(&product).Update("name", request.String("name")).Error; err != nil {
   275              response.Error(err)
   276          }
   277      }
   278  }
   279  
   280  func Destroy(response *goyave.Response, request *goyave.Request) {
   281      product := model.Product{}
   282      db := database.Conn()
   283      result := db.Select("id").First(&product, request.Params["id"])
   284      if response.HandleDatabaseError(result) {
   285          if err := db.Delete(&product).Error; err != nil {
   286              response.Error(err)
   287          }
   288      }
   289  }
   290  ```
   291  
   292  **Learn more about controllers in the [documentation](https://goyave.dev/guide/basics/controllers.html).**
   293  
   294  ### Middleware
   295  
   296  Middleware are handlers executed before the controller handler. They are a convenient way to filter, intercept or alter HTTP requests entering your application. For example, middleware can be used to authenticate users. If the user is not authenticated, a message is sent to the user even before the controller handler is reached. However, if the user is authenticated, the middleware will pass to the next handler. Middleware can also be used to sanitize user inputs, by trimming strings for example, to log all requests into a log file, to automatically add headers to all your responses, etc.
   297  
   298  ``` go
   299  func MyCustomMiddleware(next goyave.Handler) goyave.Handler {
   300      return func(response *goyave.Response, request *goyave.Request) {
   301          // Do something
   302          next(response, request) // Pass to the next handler
   303      }
   304  }
   305  ```
   306  
   307  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**.
   308  
   309  ``` go
   310  router.Middleware(middleware.MyCustomMiddleware)
   311  ```
   312  
   313  **Learn more about middleware in the [documentation](https://goyave.dev/guide/basics/middleware.html).**
   314  
   315  
   316  ### Validation
   317  
   318  Goyave provides a powerful, yet easy way to validate all incoming data, no matter its type or its format, thanks to a large number of validation rules.
   319  
   320  Incoming requests are validated using **rules set**, which associate rules with each expected field in the request.
   321  
   322  Validation rules can **alter the raw data**. That means that when you validate a field to be number, if the validation passes, you are ensured that the data you'll be using in your controller handler is a `float64`. Or if you're validating an IP, you get a `net.IP` object.
   323  
   324  Validation is automatic. You just have to define a rules set and assign it to a route. When the validation doesn't pass, the request is stopped and the validation errors messages are sent as a response.
   325  
   326  Rule sets are defined in the same package as the controller, typically in a separate file named `request.go`. Rule sets are named after the name of the controller handler they will be used with, and end with `Request`. For example, a rule set for the `Store` handler will be named `StoreRequest`. If a rule set can be used for multiple handlers, consider using a name suited for all of them. The rules for a store operation are often the same for update operations, so instead of duplicating the set, create one unique set called `UpsertRequest`.
   327  
   328  **Example:** (`http/controller/product/request.go`)
   329  ``` go
   330  var (
   331      StoreRequest = validation.RuleSet{
   332          "name":  validation.List{"required", "string", "between:3,50"},
   333          "price": validation.List{"required", "numeric", "min:0.01"},
   334          "image": validation.List{"nullable", "file", "image", "max:2048", "count:1"},
   335      }
   336  
   337      // ...
   338  )
   339  ```
   340  
   341  Once your rules sets are defined, you need to assign them to your routes using the `Validate()` method.
   342  
   343  ``` go
   344  router.Post("/product", product.Store).Validate(product.StoreRequest)
   345  ```
   346  
   347  
   348  **Learn more about validation in the [documentation](https://goyave.dev/guide/basics/validation.html).**
   349  
   350  ### Database
   351  
   352  Most web applications use a database. In this section, we are going to see how Goyave applications can query a database, using the awesome [Gorm ORM](https://gorm.io/).
   353  
   354  Database connections are managed by the framework and are long-lived. When the server shuts down, the database connections are closed automatically. So you don't have to worry about creating, closing or refreshing database connections in your application.
   355  
   356  Very few code is required to get started with databases. There are some [configuration](https://goyave.dev/guide/configuration.html#configuration-reference) options that you need to change though:
   357  
   358  - `database.connection`
   359  - `database.host`
   360  - `database.port`
   361  - `database.name`
   362  - `database.username`
   363  - `database.password`
   364  - `database.options`
   365  - `database.maxOpenConnection`
   366  - `database.maxIdleConnection`
   367  - `database.maxLifetime`
   368  
   369  ``` go
   370  user := model.User{}
   371  db := database.Conn()
   372  db.First(&user)
   373  
   374  fmt.Println(user)
   375  ```
   376  
   377  Models are usually just normal Golang structs, basic Go types, or pointers of them. `sql.Scanner` and `driver.Valuer` interfaces are also supported.
   378  
   379  ```go
   380  func init() {
   381      database.RegisterModel(&User{})
   382  }
   383  
   384  type User struct {
   385      gorm.Model
   386      Name         string
   387      Age          sql.NullInt64
   388      Birthday     *time.Time
   389      Email        string  `gorm:"type:varchar(100);uniqueIndex"`
   390      Role         string  `gorm:"size:255"` // set field size to 255
   391      MemberNumber *string `gorm:"unique;not null"` // set member number to unique and not null
   392      Num          int     `gorm:"autoIncrement"` // set num to auto incrementable
   393      Address      string  `gorm:"index:addr"` // create index with name `addr` for address
   394      IgnoreMe     int     `gorm:"-"` // ignore this field
   395  }
   396  ```
   397  
   398  **Learn more about using databases in the [documentation](https://goyave.dev/guide/basics/database.html).**
   399  
   400  ### Localization
   401  
   402  The Goyave framework provides a convenient way to support multiple languages within your application. Out of the box, Goyave only provides the `en-US` language.
   403  
   404  Language files are stored in the `resources/lang` directory.
   405  
   406  ```
   407  .
   408  └── resources
   409      └── lang
   410          └── en-US (language name)
   411              ├── fields.json (optional)
   412              ├── locale.json (optional)
   413              └── rules.json (optional)
   414  ```
   415  
   416  The `fields.json` file contains the field names translations and their rule-specific messages. Translating field names helps making more expressive messages instead of showing the technical field name to the user. Rule-specific messages let you override a validation rule message for a specific field.
   417  
   418  **Example:**
   419  ``` json
   420  {
   421      "email": {
   422          "name": "email address",
   423          "rules": {
   424              "required": "You must provide an :field."
   425          }
   426      }
   427  }
   428  ```
   429  
   430  The `locale.json` file contains all language lines that are not related to validation. This is the place where you should write the language lines for your user interface or for the messages returned by your controllers.
   431  
   432  **Example:**
   433  ``` json
   434  {
   435      "product.created": "The product have been created with success.",
   436      "product.deleted": "The product have been deleted with success."
   437  }
   438  ```
   439  
   440  The `rules.json` file contains the validation rules messages. These messages can have **[placeholders](https://goyave.dev/guide/basics/validation.html#placeholders)**, which will be automatically replaced by the validator with dynamic values. If you write custom validation rules, their messages shall be written in this file.
   441  
   442  **Example:**
   443  
   444  ``` json
   445  {
   446      "integer": "The :field must be an integer.",
   447      "starts_with": "The :field must start with one of the following values: :values.",
   448      "same": "The :field and the :other must match."
   449  }
   450  ```
   451  
   452  When an incoming request enters your application, the core language middleware checks if the `Accept-Language` header is set, and set the `goyave.Request`'s `Lang` attribute accordingly. Localization is handled automatically by the validator.
   453  
   454  ``` go
   455  func ControllerHandler(response *goyave.Response, request *goyave.Request) {
   456      response.String(http.StatusOK, lang.Get(request.Lang, "my-custom-message"))
   457  }
   458  ```
   459  
   460  **Learn more about localization in the [documentation](https://goyave.dev/guide/advanced/localization.html).**
   461  
   462  ### Testing
   463  
   464  Goyave provides an API to ease the unit and functional testing of your application. This API is an extension of [testify](https://github.com/stretchr/testify). `goyave.TestSuite` inherits from testify's `suite.Suite`, and sets up the environment for you. That means:
   465  
   466  - `GOYAVE_ENV` environment variable is set to `test` and restored to its original value when the suite is done.
   467  - All tests are run using your project's root as working directory. This directory is determined by the presence of a `go.mod` file.
   468  - Config and language files are loaded before the tests start. As the environment is set to `test`, you **need** a `config.test.json` in the root directory of your project.
   469  
   470  This setup is done by the function `goyave.RunTest`, so you shouldn't run your test suites using testify's `suite.Run()` function.
   471  
   472  The following example is a **functional** test and would be located in the `test` package.
   473  
   474  ``` go
   475  import (
   476      "github.com/username/projectname/http/route"
   477      "goyave.dev/goyave/v4"
   478  )
   479  
   480  type CustomTestSuite struct {
   481      goyave.TestSuite
   482  }
   483  
   484  func (suite *CustomTestSuite) TestHello() {
   485      suite.RunServer(route.Register, func() {
   486          resp, err := suite.Get("/hello", nil)
   487          suite.Nil(err)
   488          suite.NotNil(resp)
   489          if resp != nil {
   490              defer resp.Body.Close()
   491              suite.Equal(200, resp.StatusCode)
   492              suite.Equal("Hi!", string(suite.GetBody(resp)))
   493          }
   494      })
   495  }
   496  
   497  func TestCustomSuite(t *testing.T) {
   498      goyave.RunTest(t, new(CustomTestSuite))
   499  }
   500  ```
   501  
   502  When writing functional tests, you can retrieve the response body  easily using `suite.GetBody(response)`.
   503  
   504  ``` go 
   505  resp, err := suite.Get("/get", nil)
   506  suite.Nil(err)
   507  if err == nil {
   508      defer resp.Body.Close()
   509      suite.Equal("response content", string(suite.GetBody(resp)))
   510  }
   511  ```
   512  
   513  **URL-encoded requests:**
   514  
   515  ``` go
   516  headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded; param=value"}
   517  resp, err := suite.Post("/product", headers, strings.NewReader("field=value"))
   518  suite.Nil(err)
   519  if err == nil {
   520      defer resp.Body.Close()
   521      suite.Equal("response content", string(suite.GetBody(resp)))
   522  }
   523  ```
   524  
   525  **JSON requests:**
   526  
   527  ``` go
   528  headers := map[string]string{"Content-Type": "application/json"}
   529  body, _ := json.Marshal(map[string]interface{}{"name": "Pizza", "price": 12.5})
   530  resp, err := suite.Post("/product", headers, bytes.NewReader(body))
   531  suite.Nil(err)
   532  if err == nil {
   533      defer resp.Body.Close()
   534      suite.Equal("response content", string(suite.GetBody(resp)))
   535  }
   536  ```
   537  
   538  **Testing JSON response:**
   539  
   540  ``` go
   541  suite.RunServer(route.Register, func() {
   542      resp, err := suite.Get("/product", nil)
   543      suite.Nil(err)
   544      if err == nil {
   545          defer resp.Body.Close()
   546          json := map[string]interface{}{}
   547          err := suite.GetJSONBody(resp, &json)
   548          suite.Nil(err)
   549          if err == nil { // You should always check parsing error before continuing.
   550              suite.Equal("value", json["field"])
   551              suite.Equal(float64(42), json["number"])
   552          }
   553      }
   554  })
   555  ```
   556  
   557  The testing API has many more features such as record generators, factories, database helpers, a middleware tester, support for multipart and file uploads...
   558  
   559  **Learn more about testing in the [documentation](https://goyave.dev/guide/advanced/testing.html).**
   560  
   561  ### Status handlers
   562  
   563  Status handlers are regular handlers executed during the finalization step of the request's lifecycle if the response body is empty but a status code has been set. Status handler are mainly used to implement a custom behavior for user or server errors (400 and 500 status codes).
   564  
   565  The following file `http/controller/status/status.go` is an example of custom 404 error handling:
   566  ``` go
   567  package status
   568  
   569  import "goyave.dev/goyave/v4"
   570  
   571  func NotFound(response *goyave.Response, request *goyave.Request) {
   572      if err := response.RenderHTML(response.GetStatus(), "errors/404.html", nil); err != nil {
   573          response.Error(err)
   574      }
   575  }
   576  ```
   577  
   578  Status handlers are registered in the **router**.
   579  
   580  ``` go
   581  // Use "status.NotFound" for empty responses having status 404 or 405.
   582  router.StatusHandler(status.NotFound, 404)
   583  ```
   584  
   585  **Learn more about status handlers in the [documentation](https://goyave.dev/guide/advanced/status-handlers.html).**
   586  
   587  
   588  ### CORS
   589  
   590  Goyave provides a built-in CORS module. CORS options are set on **routers**. If the passed options are not `nil`, the CORS core middleware is automatically added.
   591  
   592  ``` go
   593  router.CORS(cors.Default())
   594  ```
   595  
   596  CORS options should be defined **before middleware and route definition**. All of this router's sub-routers **inherit** CORS options by default. If you want to remove the options from a sub-router, or use different ones, simply create another `cors.Options` object and assign it.
   597  
   598  `cors.Default()` can be used as a starting point for custom configuration.
   599  
   600  ``` go
   601  options := cors.Default()
   602  options.AllowedOrigins = []string{"https://google.com", "https://images.google.com"}
   603  router.CORS(options)
   604  ```
   605  
   606  **Learn more about CORS in the [documentation](https://goyave.dev/guide/advanced/cors.html).**
   607  
   608  ### Authentication
   609  
   610  Goyave provides a convenient and expandable way of handling authentication in your application. Authentication can be enabled when registering your routes:
   611  
   612  ``` go
   613  import "goyave.dev/goyave/v4/auth"
   614  
   615  //...
   616  
   617  authenticator := auth.Middleware(&model.User{}, &auth.BasicAuthenticator{})
   618  router.Middleware(authenticator)
   619  ```
   620  
   621  Authentication is handled by a simple middleware calling an **Authenticator**. This middleware also needs a model, which will be used to fetch user information on a successful login.
   622  
   623  Authenticators use their model's struct fields tags to know which field to use for username and password. To make your model compatible with authentication, you must add the `auth:"username"` and `auth:"password"` tags:
   624  
   625  ``` go
   626  type User struct {
   627      gorm.Model
   628      Email    string `gorm:"type:char(100);uniqueIndex" auth:"username"`
   629      Name     string `gorm:"type:char(100)"`
   630      Password string `gorm:"type:char(60)" auth:"password"`
   631  }
   632  ```
   633  
   634  When a user is successfully authenticated on a protected route, its information is available in the controller handler, through the request `User` field.
   635  
   636  ``` go
   637  func Hello(response *goyave.Response, request *goyave.Request) {
   638      user := request.User.(*model.User)
   639      response.String(http.StatusOK, "Hello " + user.Name)
   640  }
   641  ```
   642  
   643  **Learn more about authentication in the [documentation](https://goyave.dev/guide/advanced/authentication.html).**
   644  
   645  ### Rate limiting
   646  
   647  Rate limiting is a crucial part of public API development. If you want to protect your data from being crawled, protect yourself from DDOS attacks, or provide different tiers of access to your API, you can do it using Goyave's built-in rate limiting middleware.
   648  
   649  This middleware uses either a client's IP or an authenticated client's ID (or any other way of identifying a client you may need) and maps a quota, a quota duration and a request count to it. If a client exceeds the request quota in the given quota duration, this middleware will block and return `HTTP 429 Too Many Requests`.
   650  
   651  The middleware will always add the following headers to the response:
   652  - `RateLimit-Limit`: containing the requests quota in the time window
   653  - `RateLimit-Remaining`: containing the remaining requests quota in the current window
   654  - `RateLimit-Reset`: containing the time remaining in the current window, specified in seconds
   655  
   656  ```go
   657  import "goyave.dev/goyave/v4/middleware/ratelimiter"
   658  
   659  ratelimiterMiddleware := ratelimiter.New(func(request *goyave.Request) ratelimiter.Config {
   660      return ratelimiter.Config {
   661          RequestQuota:  100,
   662          QuotaDuration: time.Minute,
   663          // 100 requests per minute allowed
   664          // Client IP will be used as identifier
   665      }
   666  })
   667  
   668  router.Middleware(ratelimiterMiddleware)
   669  ```
   670  
   671  **Learn more about rate limiting in the [documentation](https://goyave.dev/guide/advanced/rate-limiting.html).**
   672  
   673  ### Websocket
   674  
   675  Goyave is using [`gorilla/websocket`](https://github.com/gorilla/websocket) and adds a layer of abstraction to it to make it easier to use. You don't have to write the connection upgrading logic nor the close handshake. Just like regular HTTP handlers, websocket handlers benefit from reliable error handling and panic recovery.
   676  
   677  Here is an example of an "echo" feature:
   678  ```go
   679  upgrader := websocket.Upgrader{}
   680  router.Get("/websocket", upgrader.Handler(func(c *websocket.Conn, request *goyave.Request) error {
   681      for {
   682          mt, message, err := c.ReadMessage()
   683          if err != nil {
   684              return err
   685          }
   686          goyave.Logger.Printf("recv: %s", message)
   687          err = c.WriteMessage(mt, message)
   688          if err != nil {
   689              return fmt.Errorf("write: %w", err)
   690          }
   691      }
   692  }))
   693  ```
   694  
   695  **Learn more about websockets in the [documentation](https://goyave.dev/guide/advanced/websocket.html).**
   696  
   697  ## Contributing
   698  
   699  Thank you for considering contributing to the Goyave framework! You can find the contribution guide in the [documentation](https://goyave.dev/guide/contribution-guide.html).
   700  
   701  I have many ideas for the future of Goyave. I would be infinitely grateful to whoever want to support me and let me continue working on Goyave and making it better and better.
   702  
   703  You can support me on Github Sponsor.
   704  
   705  <a href="https://github.com/sponsors/System-Glitch">❤ Sponsor me!</a>
   706  
   707  I'm very grateful to my patrons, sponsors and donators:
   708  
   709  - Ben Hyrman
   710  - Massimiliano Bertinetti
   711  - ethicnology
   712  - Yariya
   713  - sebastien-d-me
   714  - Nebojša Koturović
   715  
   716  ### Contributors
   717  
   718  A big "Thank you" to the Goyave contributors:
   719  
   720  - [Kuinox](https://github.com/Kuinox) (Powershell install script)
   721  - [Alexandre GV.](https://github.com/alexandregv) (Install script MacOS compatibility)
   722  - [jRimbault](https://github.com/jRimbault) (CI and code analysis)
   723  - [Guillermo Galvan](https://github.com/gmgalvan) (Request extra data)
   724  - [Albert Shirima](https://github.com/agbaraka) (Rate limiting and various contributions)
   725  - [Łukasz Sowa](https://github.com/Morishiri) (Custom claims in JWT)
   726  - [Zao SOULA](https://github.com/zaosoula) (Custom `gorm.Config{}` in config file)
   727  - [Ajtene Kurtaliqi](https://github.com/akurtaliqi) (Documentation landing page)
   728  - [Louis Laurent](https://github.com/ulphidius) ([`gyv`](https://github.com/go-goyave/gyv) productivity CLI)
   729  - [Clement3](https://github.com/Clement3) (`search` feature on [`goyave.dev/filter`](https://github.com/go-goyave/filter))
   730  - [Darkweak](https://github.com/darkweak) (`HTTP cache, RFC compliant` middleware based on [Souin HTTP cache system](https://github.com/darkweak/souin))
   731  - [Jason C Keller](https://github.com/imuni4fun) (Testify interface compatibility)
   732  
   733  ## Used by
   734  
   735  <p align="center">
   736      <a href="https://adagio.io" target="_blank" rel="nofollow">
   737          <img src=".github/usedby/adagio.webp" alt="Adagio.io"/>
   738      </a>
   739  </p>
   740  
   741  <p align="center">
   742      Do you want to be featured here? <a href="https://github.com/go-goyave/goyave/issues/new?template=used_by.md" target="_blank" rel="nofollow">Open an issue</a>.
   743  </p>
   744  
   745  ## License
   746  
   747  The Goyave framework is MIT Licensed. Copyright © 2019 Jérémy LAMBERT (SystemGlitch)