📖 Go Fiber by Examples: Delving into built-in functions
Tags: go, beginners, tutorial, showdev
Published: 2021-08-24 19:33:10

## Introduction

Hey, DEV friends! 👋 

As promised in last week's post, today I've posted the slightly edited **Chapter 2** from my book for the Packt Publisher that didn't happen. If you missed it, I told that at the beginning of [previous article](https://dev.to/koddr/go-fiber-by-examples-how-can-the-fiber-web-framework-be-useful-487a).

## Plan for the Chapter 2

In this second article (or chapter), we will get even closer to the inner workings of the [Fiber web framework](https://github.com/gofiber/fiber), its routing technique, built-in components and methods.

In this article, we’re going to cover the following main topics 👇

<a name="toc"></a>
### 📝 Table of contents

- [Fiber application](#fiber-application)
- [Configuration](#configuration)
- [Routing technique](#routing-technique)
  - [Simple routes](#simple-routes)
  - [Named routes](#named-routes)
  - [Routes with greedy parameters](#routes-with-greedy-parameters)
  - [More complex routes](#more-complex-routes)
  - [Limitations for characters in the path](#limitations-for-characters-in-the-path)
  - [Regexp routes](#regexp-routes)
- [Built-in methods](#built-in-methods)
  - [Static](#static)
  - [Route Handlers](#route-handlers)
  - [Mount](#mount)
  - [Group](#group)
  - [Server](#server)
  - [Stack](#stack)
  - [Config](#config)
  - [Handler](#handler)
  - [Listen](#listen)
  - [ListenTLS](#listentls)
  - [Listener](#listener)
  - [Test](#test)
  - [NewError](#newerror)
- [Working with Fiber Context methods](#working-with-fiber-context-methods)
  - [BodyParser](#bodyparser)
  - [JSON](#json)
  - [Params](#params)
  - [Query](#query)
  - [Set](#set)
  - [Status and SendStatus](#status-and-sendstatus)
- [Summary](#summary)

<a name="#fiber-application"></a>
## Fiber application 

Like many other web frameworks, the **Fiber** application also starts with the creation of a new named instance. To create, simply import the package and call the `fiber.New` method:

```go
// ./go/app.go

import "github.com/gofiber/fiber/v2"

func main() {
  // Create a new Fiber instance, called 'app'
  app := fiber.New()

  // ...
}
```

After executing, a new Fiber instance will be created in the app variable with the default configuration. We will cover manual configuration of the instance later in this article.

[↑ Table of contents](#toc)

<a name="#configuration"></a>
### Configuration

Sometimes, the default settings are not enough to configure an application the way we need it. To satisfy such users, **Fiber** has a special `fiber.Config` structure that contains many fields for fine-tuning.

For example, let's change the standard output of the server header:

```go
// Create config variable
config := fiber.Config{
  ServerHeader: "My Server", // add custom server header
}

// Create a new Fiber instance with custom config
app := fiber.New(config)
```

After that, every request to that application will return that server name along with a Response header. In a real application, it might look like this:

```console
Access-Control-Allow-Origin: *
Content-Length: 51
Content-Type: application/json
Date: Mon, 03 May 2021 07:00:39 GMT
Server: My Server
Vary: Origin
```

**Simple, isn't it?** 🤔 Let's now list all of the existing **Fiber** application configuration fields and go into a little more detail about each one.

#### Prefork

Type: `bool`, default: `false`.

Enables use of the `SO_REUSEPORT` socket option. This will spawn multiple **Go** processes listening on the same port. Also, it's called socket sharding. If enabled, the application will need to be run through a shell because prefork mode sets environment variables.

> ☝️ **Note:** When using **Docker**, make sure the application is running with `CMD ./app` or `CMD ["sh", "-c", "/app"]` into project's `Dockerfile`.

#### ServerHeader

Type: `string`, default: `""` (empty string).

Enables the Server HTTP header with the given value.

#### StrictRouting

Type: `bool`, default: `false`.

When enabled, the Fiber router treats `/foo` and `/foo/` as different routes. This can be useful, if we want to improve the **SEO** (Search Engine Optimization) of the website.

#### CaseSensitive

Type: `bool`, default: `false`.

When enabled, the **Fiber** router treats `/Foo` and `/foo` as different routes.

#### Immutable

Type: `bool`, default: `false`.

When enabled, all values returned by context methods are immutable. By default, they are valid until you return from the handler.

#### UnescapePath

Type: `bool`, default: `false`.

Converts all encoded characters in the route back before setting the path for the context, so that the routing can also work with URL encoded special characters.

#### ETag

Type: `bool`, default: `false`.

Enable [ETag](https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/ETag) header generation, since both weak and strong etags are generated using the same hashing method ([CRC-32](https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm)).

#### BodyLimit

Type: `int`, default: `4 * 1024 * 1024`.

Sets the maximum allowed size for a request body. If the size exceeds the configured limit, it sends [HTTP 413 Payload Too Large](https://developer.mozilla.org/ru/docs/Web/HTTP/Status/413) response.

#### Concurrency

Type: `int`, default: `256 * 1024`.

Maximum number of concurrent connections.

#### Views

`Views` is the interface to provide your own template engine and contains `Load` and `Render` methods. 

The `Load` method is executed by **Fiber** on app initialization to load/parse the templates. And the `Render` method is linked to the `ctx.Render` function that accepts a template name and binding data.

The **Fiber** team supports [template](https://github.com/gofiber/template) package that provides wrappers for multiple template engines:

- Standard Go's [html/template engine](https://github.com/gofiber/template/tree/master/html)
- [Ace](https://github.com/gofiber/template/tree/master/ace)
- [Amber](https://github.com/gofiber/template/tree/master/amber)
- DTL or [Django Template Language](https://github.com/gofiber/template/tree/master/django)
- [Handlebars](https://github.com/gofiber/template/tree/master/handlebars)
- [Jet](https://github.com/gofiber/template/tree/master/jet)
- [Mustache](https://github.com/gofiber/template/tree/master/mustache)
- [Pug](https://github.com/gofiber/template/tree/master/pug)

Here's a simple example of how to use it:

```go
// ./go/views.go

package main

import (
  "github.com/gofiber/fiber/v2"
  "github.com/gofiber/template/html" // add engine
)

func main() {
  // Initialize a standard Go's html/template engine
  engine := html.New("./views", ".html")

  // Create a new Fiber template with template engine
  app := fiber.New(fiber.Config{
    Views: engine,
  })

  app.Get("/", func(c *fiber.Ctx) error {
    // Render a template named 'index.html' with content
    return c.Render("index", fiber.Map{
      "Title":       "Hello, World!",
      "Description": "This is a template.",
    })
  })

  // Start server on port 3000
  app.Listen(":3000")
}
```

And the HTML template itself for rendering content in the `./views` folder:

```html
<!-- ./go/views/index.html -->

<!DOCTYPE html>
<head>
  <title>{{.Title}}</title>
</head>
<body>
  <h1>{{.Title}}</h1>
  <p>{{.Description}}</p>
</body>
</html>
```

By running this code (`go run ./go/views.go`) and going to `http://localhost:3000/`, we will see that the code works exactly as we expected:

![Screenshot 1: The result of the template rendering](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j87rh2biro0od7tf0ufg.png)

#### ReadTimeout

Type: `time.Duration`, default: `nil`.

The amount of time allowed to read the full request, including the body. Set to `nil` for unlimited timeout.

#### WriteTimeout

Type: `time.Duration`, default: `nil`.

The maximum duration before timing out writes of the response. Set to `nil` for unlimited timeout.

#### IdleTimeout

Type: `time.Duration`, default: `nil`.

The maximum amount of time to wait for the next request when keep-alive is enabled.

> ☝️ **Note:** If IdleTimeout is zero, the value of ReadTimeout is used.

#### ReadBufferSize

Type: `int`, default: `4096`.

Per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer, if your clients send multi-KB RequestURIs and/or multi-KB headers.

#### WriteBufferSize

Type: `int`, default: `4096`.

Per-connection buffer size for responses' writing.

#### CompressedFileSuffix

Type: `string`, default: `".fiber.gz"`.

Adds a suffix to the original file name and tries saving the resulting compressed file under the new file name.

#### ProxyHeader

Type: `string`, default: `""` (empty string).

This will enable `ctx.IP` to return the value of the given header key. By default, `ctx.IP` will return the Remote IP from the TCP connection.

> ☝️ **Note:** This property can be useful if you are behind a load balancer, e.g. `X-Forwarded-*`.

#### GETOnly

Type: `bool`, default: `false`.

Enables to rejects all non-GET requests. This option is useful as anti-DoS protection for servers accepting only GET requests.

> ☝️ **Note:** If `GETOnly` is set to true, the request size is limited by `ReadBufferSize`.

#### ErrorHandler

Type: `ErrorHandler`, default: `DefaultErrorHandler`.

`ErrorHandler` is executed, when an error is returned from `fiber.Handler`.

#### DisableKeepalive

Type: `bool`, default: `false`.

Disable keep-alive connections. The server will close incoming connections after sending the first response to the client.

#### DisableDefaultDate

Type: `bool`, default: `false`.

When set to `true` causes the default date header to be excluded from the response.

#### DisableDefaultContentType

Type: `bool`, default: `false`.

When set to true, causes the default `Content-Type` header to be excluded from the Response.

#### DisableHeaderNormalizing

Type: `bool`, default: `false`.

By default, all header names are normalized. For example, header `cOnteNT-tYPE` will convert to more readable `Content-Type`.

#### DisableStartupMessage

Type: `bool`, default: `false`.

When set to true, it will not print out debug information and startup message, like this:

```console
┌───────────────────────────────────────────────────┐ 
│                    Fiber v2.17.0                  │ 
│               http://127.0.0.1:5000               │ 
│       (bound on host 0.0.0.0 and port 5000)       │ 
│                                                   │ 
│ Handlers ............ 21  Processes ........... 1 │ 
│ Prefork ....... Disabled  PID ............. 92607 │ 
└───────────────────────────────────────────────────┘
```

[↑ Table of contents](#toc)

<a name="#routing-technique"></a>
## Routing technique

The central part of any application, especially if it's a REST API, is routing requests to the appropriate endpoints. Fiber has an excellent set of options for creating a router for any task.

> ☝️ **Note:** Route paths, combined with a request method, define the endpoints at which requests can be made. Route paths can be **strings** or **string patterns**.

Route patterns are dynamic elements in the route, which are named or not named segments. This segments that are used to capture the values specified at their position in the URL.

The obtained values can be retrieved using the `ctx.Params` function, with the name of the route pattern specified in the path as their respective keys or for unnamed patterns the character (`*` or `+`) and the counter of this.

- The characters `:`, `+`, and `*` are characters that introduce a pattern.
- Greedy patterns are indicated by wildcard (`*`) or plus (`+`) signs.

The routing also offers the possibility to use optional patterns, for the named patterns these are marked with a final `?` sign, unlike the plus sign which is not optional. You can use the wildcard character for a pattern range which is optional and greedy.

Let's go over them with some real-world examples.

[↑ Table of contents](#toc)

<a name="#simple-routes"></a>
### Simple routes

This route path will match requests to the root route, `/`:

```go
app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("root")
})
```

This route path will match requests to `/about`:

```go
app.Get("/about", func(c *fiber.Ctx) error {
  return c.SendString("about")
})
```

This route path will match requests to `/random.txt`, not a file with the same name, as you might think. We will talk about how to serve a file later in this article.

```go
app.Get("/random.txt", func(c *fiber.Ctx) error {
  return c.SendString("random.txt")
})
```

[↑ Table of contents](#toc)

<a name="#named-routes"></a>
### Named routes

This dynamic path example will expect the author name (_in the author parameter_) and book title (_in the title parameter_) to be output when queried:

```go
app.Get("/library/:author/books/:title", func(c *fiber.Ctx) error {
  str := fmt.Sprintf("%s, %s", c.Params("author"), c.Params("title"))
  return c.SendString(str)
})
```

If you call this path in the running **Fiber** application like `http://localhost:3000/user/Tolkien/books/Hobbit`. Then this line will be displayed: `Tolkien, Hobbit`.

Sometimes, we can't know right away if a parameter will be passed to a URL. For this, the **Fiber** developers introduced optional parameters:

```go
app.Get("/user/:name?", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("name"))
})
```

It returns empty string, if name is not specified.

[↑ Table of contents](#toc)

<a name="#routes-with-greedy-parameters"></a>
### Routes with greedy parameters

The **Fiber** web framework also supports so-called greedy parameters. Such parameters will be useful when we have a task to build an address for an endpoint with previously unknown parameters. They can be either optional or required.

Let's look at an example of a required greedy parameter in the example below:

```go
app.Get("/user/+", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("+"))
})
```

In the place where there is a plus sign, we must necessarily pass parameters. But we are not limited to anything, as we can pass either a single parameter or a whole chain of parameters:

```console
http://localhost:3000/user/?name=Bilbo
http://localhost:3000/user/?name=Bilbo&family=Baggins&city=Shire
```

The optional greedy parameters work similarly:

```go
app.Get("/user/*", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("*"))
})
```

If there are several wildcards in one endpoint, just add a number (_right to left_) to the asterisk to get them. For example, like this:

```go
app.Get("/user/*/work/*/job/*", func(c *fiber.Ctx) error {
  c.SendString(c.Params("*1")) // first wildcard
  c.SendString(c.Params("*2")) // second wildcard
  c.SendString(c.Params("*3")) // third wildcard
  // ...
})
```

[↑ Table of contents](#toc)

<a name="#more-complex-routes"></a>
### More complex routes

Since the hyphen (`-`) and the dot (`.`) are interpreted literally, they can be used along with route parameters for useful purposes. **Fiber**'s intelligent router recognizes that the introductory parameter characters should be part of the request route in this case and can process them as such.

This allows us to build very complex endpoint paths, for almost any task:

```go
app.Get("/flights/:from-:to/time::at", func(c *fiber.Ctx) error {
  str := fmt.Sprintf("%s-%s at %s", c.Params("from"), c.Params("to"), c.Params("at"))
  return c.SendString(str)
})
```

By sending a request to this URL `http://localhost:3000/flights/LAX-SFO/time:10PM`, we get the string `LAX-SFO` at `10PM`. As we expected at the beginning.

Thus, **Fiber** was able to support a fairly complex route, but for the user such a record is still as clear as possible!

[↑ Table of contents](#toc)

<a name="#limitations-for-characters-in-the-path"></a>
### Limitations for characters in the path

All special characters in path must be escaped with backslash (`\`) for lose their original value. For example, if route path must match to `/resource/key:value`, we need to escape colon (`:`) sign, like this:

```go
app.Get("/resource/key\\:value", func(c *fiber.Ctx) error {
  return c.SendString("escaped key:value")
})
```

[↑ Table of contents](#toc)

<a name="#regexp-routes"></a>
### Regexp routes

The **Fiber** web framework aims to be one of the fastest and clearest web frameworks in **Go**, so deliberately slowing down routing for the sake of supporting a rather specific case is not in the developers' plans.

And, yes, **Fiber** does not currently support regular expressions in routes, like other frameworks. But it's not so important, because most of the routing cases can close the techniques described above.

[↑ Table of contents](#toc)

<a name="#built-in-methods"></a>
## Built-in methods

And now let's talk about the methods built into the **Fiber** web framework that are designed to ease most of the routine operations so that you write less duplicate code.

[↑ Table of contents](#toc)

<a name="#static"></a>
### Static

Use the `Static` method to serve static files such as images, CSS, and JavaScript. By default, it will serve `index.html` files in response to a request on a directory.

The following code serves all files and folders in the directory named `./public` (in the root folder of our project):

```go
app.Static("/", "./public")
```

By running the application, we can access the contents of that folder at these addresses (of course, if they are there):

```console
http://localhost:3000/page.html
http://localhost:3000/js/script.js
http://localhost:3000/css/style.css
```

Yes, we can easily serve files in completely different directories within a single **Fiber** application, for example:

```go
// Serve files from './public' directory
app.Static("/", "./public")

// Serve files from './storage/user-uploads' directory
app.Static("/files", "./storage/user-uploads")
```

This method is great for creating a complete **SPA** (Single Page Application).

Also, the `Static` method has settings that allow you to fine-tune the behavior of the **Fiber** application when serving files. To access them, call the method with the `fiber.Static` interface as the third argument:

```go
// Create a new config for Static method
config := fiber.Static{
  Compress:      true,
  ByteRange:     true,
  Browse:        true,
  Index:         "page.html"
  CacheDuration: 60 * time.Second,
  MaxAge:        3600,
  Next:          nil
}

// Serve files from './public' directory with config
app.Static("/", "./public", config)
```
Let's break down each setting item in more detail.

#### Compress

Type: `bool`, default: `false`.

When set to true, the server tries minimizing CPU usage by caching compressed files.

> ☝️ **Note:** This works differently than the [compression middleware](https://github.com/gofiber/compression), which is supported by the **Fiber** team.

#### ByteRange

Type: `bool`, default: `false`.

When set to `true`, enables byte range requests.

#### Browse

Type: `bool`, default: `false`.

When set to `true`, enables directory browsing.

#### Index

Type: `string`, default: `"index.html"`.

The name of the index file for serving a directory.

#### CacheDuration

Type: `time.Duration`, default: `10 * time.Second`.

Expiration duration for inactive file handlers. Use a negative `time.Duration` to disable it.

#### MaxAge

Type: `int`, default: `0`.

The value for the `Cache-Control` HTTP header that is set on the file response. `MaxAge` is defined in seconds.

#### Next

Type: `func(c *Ctx) bool`, default: `nil`.

Next defines a function to skip this middleware, when `true` is returned.

> ☝️ **Note:** The setting can be useful when it is necessary to serve a folder with files, as a result of some external state changes or user requests in the application.

[↑ Table of contents](#toc)

<a name="#route-handlers"></a>
### Route Handlers

Use the following methods for register a route bound to a specific HTTP method.

- [Get](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET)
- [Post](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)
- [Put](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT)
- [Patch](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH)
- [Delete](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE)
- [Head](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD)
- [Connect](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT)
- [Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS)
- [Trace](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/TRACE)

```go
// Create a new route with GET method
app.Get("/", handler)

// Create a new route with POST method
app.Post("/article/add", handler)

// Create a new route with PUT method
app.Put("/article/:id/edit", handler)

// Create a new route with PATCH method
app.Patch("/article/:id/edit", handler)

// Create a new route with DELETE method
app.Delete("/article/:id", handler)

// ...
```

The **Fiber** Web Framework has the following helper methods for handling HTTP methods: `Add` and `All`.

The `Add` method allows you to use an HTTP method, as the value:

```go
// Set HTTP method to variable
method := "POST"

// Create a new route with this method
app.Add(method, "/form/create", handler)
```

And the `All` method opens up possibilities for us to register a route that can accept any valid HTTP methods, which can be handy in some cases:

```go
// Create a new route for all HTTP methods
app.All("/all", handler)
```

[↑ Table of contents](#toc)

<a name="#mount"></a>
### Mount

Use the `Mount` method for mount one Fiber instance to another by creating the `*Mount` struct.

```go
// ./go/mount.go

package main

import "github.com/gofiber/fiber/v2"

func main() {
  // Create the first Fiber instance
  micro := fiber.New()

  // Create a new route for the first instance
  micro.Get("/doe", func(c *fiber.Ctx) error {
    return c.SendStatus(fiber.StatusOK) // send HTTP 200 OK
  })

  // Create the second Fiber instance
  app := fiber.New()

  // Create a new route for the second instance,
  // with included first instance's route
  app.Mount("/john", micro)

  // Start server on port 3000
  app.Listen(":3000")
}
```

The `/john/doe` route of this **Fiber** application will now give a status [HTTP 200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200).

[↑ Table of contents](#toc)

<a name="#group"></a>
### Group

Use `Group` method for grouping routes by creating the `*Group` struct.

```go
// ./go/group.go

package main

import "github.com/gofiber/fiber/v2"

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create a new route group '/api'
  api := app.Group("/api", handler)

  // Create a new route for API v1
  v1 := api.Group("/v1", handler)
  v1.Get("/list", handler)

  // Create a new route for API v1
  v2 := api.Group("/v2", handler)
  v2.Get("/list", handler)

  // Start server on port 3000
  app.Listen(":3000")
}
```

This built-in method is great for versioning our application's API.

[↑ Table of contents](#toc)

<a name="#server"></a>
### Server

Use `Server` method for returns the underlying [fasthttp](https://pkg.go.dev/github.com/valyala/fasthttp#Server) server.

```go
// Set the fasthttp option 'MaxConnsPerIP' to '1'
app.Server().MaxConnsPerIP = 1
```

[↑ Table of contents](#toc)

<a name="#stack"></a>
### Stack

Use `Stack` method for return the original router stack.

```go
// ./go/stack.go

package main

import (
  "encoding/json"
  "fmt"

  "github.com/gofiber/fiber/v2"
)

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create new routes
  app.Get("/john/:age", handler)
  app.Post("/register", handler)

  // Print the router stack in JSON format
  data, _ := json.MarshalIndent(app.Stack(), "", "  ")
  fmt.Println(string(data))

  // Start server on port 3000
  app.Listen(":3000")
}
```

The result will be a list of all routes in a nicely formatted JSON format:

```json
[
  [
    {
      "method": "GET",
      "path": "/john/:age",
      "params": [
        "age"
      ]
    }
  ],
  [
    {
      "method": "POST",
      "path": "/register",
      "params": null
    }
  ]
]
```

[↑ Table of contents](#toc)

<a name="#config"></a>
### Config

Use `Config` method for return the app config as value (read-only).

```go
// Print ServerHeader value
fmt.Println(app.Config().ServerHeader)
```

[↑ Table of contents](#toc)

<a name="#handler"></a>
### Handler

Use `Handler` method for return the server handler that can be used to serve custom `*fasthttp.RequestCtx` requests (more info about this is [here](ttps://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx)).

[↑ Table of contents](#toc)

<a name="#listen"></a>
### Listen

Use `Listen` method for serve HTTP requests from the given address.

```go
// Listen on port 8080 
app.Listen(":8080")

// Listen on the custom host and port
app.Listen("127.0.0.2:9090")
```

[↑ Table of contents](#toc)

<a name="#listentls"></a>
### ListenTLS

User `ListenTLS` method for serve HTTPS (_secure HTTP_) requests from the given address using `certFile` and `keyFile` paths to TLS certificate and key.

```go
// Listen on port 443 with TLS cert and key
app.ListenTLS(":443", "./cert.pem", "./cert.key")
```

[↑ Table of contents](#toc)

<a name="#listener"></a>
### Listener

Use `Listener` method for pass custom [net.Listener](https://golang.org/pkg/net/#Listener). This method can be used to enable TLS/HTTPS with a custom [tls.Config](https://golang.org/pkg/crypto/tls/#Config).

```go
// Create a new net.Listener TCP instance on port 3000
ln, _ := net.Listen("tcp", ":3000")

// Set TLS key pair (certificate and key)
certs, _ := tls.LoadX509KeyPair("./server.crt", "./server.key")

// Configure a new TLS listener with params
lr := tls.NewListener(
  ln,
  &tls.Config{
    Certificates: []tls.Certificate{
      certs,
    },
  },
)

// Start server with TLS listener
app.Listener(lr)
```

[↑ Table of contents](#toc)

<a name="#test"></a>
### Test

Testing your application is done with the Test method. Use this method when you need to debug your routing logic.

We will consider this method in more detail at the next article. **Stay tuned!** 😉

[↑ Table of contents](#toc)

<a name="#newerror"></a>
### NewError

Use `NewError` method for create a new HTTP error instance with an optional message.

```go
// Create a custom error with HTTP code 782
app.Get("/error", func(c *fiber.Ctx) error {
  return fiber.NewError(782, "Custom error message")
})
IsChild
Use IsChild method for determine, if the current process is a result of Prefork.
// Create a new Fiber instance with config
app := fiber.New(fiber.Config{
  Prefork: true, // enable Prefork
})

// Cheking current process
if fiber.IsChild() {
  fmt.Println("I'm a child process")
} else {
  fmt.Println("I'm the parent process")
}

// ...
```

[↑ Table of contents](#toc)

<a name="#working-with-fiber-context-methods"></a>
## Working with Fiber Context methods

In the **Fiber** web framework you will find a huge variety of methods for working with request contexts. As of `v2.17.0`, there are a total of **55**, and this number grows with each major version. Therefore, we will not go through them all, so as not to waste our time, but focus only on those that we will use in this series (in its practical part).

> ☝️ **Note:** For a complete list of all `Context` methods, its signatures and code examples, please visit the official documentation page of the **Fiber** web framework at https://docs.gofiber.io/api/ctx

[↑ Table of contents](#toc)

<a name="#bodyparser"></a>
### BodyParser

Binds the request body to a struct. `BodyParser` supports decoding query parameters and the following content types based on the `Content-Type` header:

- application/json
- application/xml
- application/x-www-form-urlencoded
- multipart/form-data

```go
// ./go/body_parser.go

package main

import (
  "fmt"

  "github.com/gofiber/fiber/v2"
)

// Define the Person struct
type Person struct {
  Name  string `json:"name" xml:"name" form:"name"`
  Email string `json:"email" xml:"email" form:"email"`
}

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create a new route with POST method
  app.Post("/create", func(c *fiber.Ctx) error {
    // Define a new Person struct
    person := new(Person)

    // Binds the request body to the Person struct
    if err := c.BodyParser(person); err != nil {
      return err
    }

    // Print data from the Person struct
    fmt.Println(person.Name, person.Email)

    return nil
  })

  // Start server on port 3000
  app.Listen(":3000")
}
```

If we run this application and send data from the form to the route `http://localhost:3000/create` by POST, we will see in the console the data we sent.

> ☝️ **Note:** Field names in a struct should start with an uppercase letter.

[↑ Table of contents](#toc)

<a name="#json"></a>
### JSON

Converts any interface or string to JSON using the [segmentio/encoding](https://github.com/segmentio/encoding) package. Also, the JSON method sets the content header to `application/json`.

```go
// ./go/json.go

package main

import "github.com/gofiber/fiber/v2"

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create a new route with GET method
  app.Get("/json", func(c *fiber.Ctx) error {
    // Return response in JSON format
    return c.JSON(fiber.Map{
      "name": "John",
      "age":  33,
    })
  })

  // Start server on port 3000
  app.Listen(":3000")
}
```

As we could see, in this example a special helper method `fiber.Map` was used, which is just an empty **Go** interface. The result of this application will display data in JSON format: `{"name": "John", "age": 33}`.

[↑ Table of contents](#toc)

<a name="#params"></a>
### Params

The `Params` method can be used to get the route parameters. We can pass an optional default value that will be returned, if the param key does not exist.

```go
// ./go/params.go

package main

import (
  "fmt"

  "github.com/gofiber/fiber/v2"
)

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create a new route with named params
  app.Get("/user/:name", func(c *fiber.Ctx) error {
    // Print name from params
    fmt.Println(c.Params("name"))

    return nil
  })

  // Create a new route with optional greedy params
  app.Get("/user/*", func(c *fiber.Ctx) error {
    // Print all data, given from '*' param
    fmt.Println(c.Params("*"))

    return nil
  })

  // Start server on port 3000
  app.Listen(":3000")
}
```

We dealt with the topic of parameters in routes in more detail earlier in this article.

[↑ Table of contents](#toc)

<a name="#query"></a>
### Query

`Query` method is an object containing a property for each query string parameter in the route. We can pass an optional default value that will be returned, if the query key does not exist.

```go
// ./go/query.go

package main

import (
  "fmt"

  "github.com/gofiber/fiber/v2"
)

func main() {
  // Create a new Fiber instance
  app := fiber.New()

  // Create a new route with query params
  app.Get("/user", func(c *fiber.Ctx) error {
    // Print name from query param
    fmt.Println(c.Query("name"))

    return nil
  })

  // Start server on port 3000
  app.Listen(":3000")
}
```

By calling this endpoint and passing the query parameter with the name key, we get its value.

[↑ Table of contents](#toc)

<a name="#set"></a>
### Set

The `Set` method sets the response’s HTTP header field to the specified key and value.

```go
// Create a new route with text/plain content type
app.Get("/text", func(c *fiber.Ctx) error {
  // Set a new Content-Type for this route
  c.Set("Content-Type", "text/plain")

  // ...
})
```

[↑ Table of contents](#toc)

<a name="#status-and-sendstatus"></a>
### Status and SendStatus

The `Status` and `SendStatus` methods set the HTTP status code for the response and the correct status message in the body, if the response body is empty. But there is a small difference in the options for using these methods.

The `Status` method is a chainable. This means that it can be used in conjunction with other methods, like this:

```go
// Create a new route with HTTP status
app.Get("/bad-request", func(c *fiber.Ctx) error {
  // Return status with a custom message
  return c.Status(fiber.StatusBadRequest).SendString("Bad Request")
})
```

And method `SendStatus` should be used only when we don't need anything except returning HTTP code. For example:

```go
// Create a new route with HTTP status
app.Get("/forbidden", func(c *fiber.Ctx) error {
  // Return only status
  return c.SendStatus(fiber.StatusForbidden)
})
```

> ☝️ **Note:** We can view all supported Fiber helpers for HTTP statuses [here](https://github.com/gofiber/fiber/blob/v2.17.0/helpers.go#L448).

[↑ Table of contents](#toc)

<a name="#summary"></a>
## Summary

So that was a very informative article! 

- We learned the basic instance of the **Fiber** framework, were able to configure it to our liking. 
- We looked at how **Fiber** works with routes, what it can and can't do with them. 
- Learned about all the necessary built-in web framework methods and learned how to work with context. 

In the next article, we will get even closer to the `Test` method.

[↑ Table of contents](#toc)

<a name=""></a>
## Photos and videos by

- Aaron Burden feat. Vic Shóstak https://unsplash.com/photos/QJDzYT_K8Xg

<a name=""></a>
## P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

- 🔥 [gowebly][gowebly_url]: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
- ✨ [create-go-app][cgapp_url]: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
- 🏃 [yatr][yatr_url]: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
- 📚 [gosl][gosl_url]: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
- 🏄‍♂️ [csv2api][csv2api_url]: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
- 🚴 [json2csv][json2csv_url]: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

<!-- Footer links -->

[gowebly_url]: https://github.com/gowebly
[cgapp_url]: https://github.com/create-go-app
[yatr_url]: https://github.com/koddr/yatr
[gosl_url]: https://github.com/koddr/gosl
[csv2api_url]: https://github.com/koddr/csv2api
[json2csv_url]: https://github.com/koddr/json2csv