Query

ctx.Request.Query provides access to the parameters of the current request URL query string.

The query parameters allow you to send additional information via the URL and are usually used for searches, filters, systems, paging and other navigation options.

For example, in the next URL the parameter page contains the value 2:

text
/products?page=2

You can consult it by ctx.Request.Query:

gox
func GET(ctx *gox.Context) gox.Page {
    page, ok := ctx.Request.Query.Get("page")

    if !ok {
        page = "1"
    }

    return <p>Page {{ page }}</p>
}

ctx.Request.Query It is a read-only collection. Its values are obtained from the URL query string and cannot be modified from the request.


Structure

ctx.Request.Query provides the following methods:

text
Query
{
    Get(key string) (string, bool)
    GetAll(key string) ([]string, bool)
    Has(key string) bool
    IsEmpty() bool
    Count() int
    Keys() []string
    Values() []string
    Entries() map[string][]string
}

Methods


Get()

Returns the first value associated with a parameter and indicates if the parameter exists.

Firma:func (Query) Get(key string) (string, bool)

The second value returned is true when the parameter exists and contains at least one value.

When the parameter does not exist, it returns an empty string and false.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?page=2

    page, ok := ctx.Request.Query.Get("page")

    // page == "2"
    // ok == true
    return <p>Page {{ page }}</p>
}

When a parameter does not exist:

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products

    page, ok := ctx.Request.Query.Get("page")

    if !ok {
        page = "1"
    }

    // page == "1"
    return <p>Page {{ page }}</p>
}

When the same parameter appears several times, Get() returns only the first value.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?tag=go&tag=web

    tag, ok := ctx.Request.Query.Get("tag")

    // tag == "go"
    // ok == true
    return <p>{{ tag }}</p>
}

Use GetAll() when you need to consult all the values associated with the parameter.


GetAll()

Returns all values associated with a parameter and indicates if the parameter exists.

Firma:func (Query) GetAll(key string) ([]string, bool)

When the parameter does not exist or contains values, it returns nil and false.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?tag=go&tag=web&tag=backend

    tags, ok := ctx.Request.Query.GetAll("tag")

    if !ok {
        return <p>No tags selected.</p>
    }

    // tags == []string{"go", "web", "backend"}
    return <ul>
        <:for tag range={{ tags }}>
            <li>{{ tag }}</li>
        </:for>
    </ul>
}

When the parameter does not exist:

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles

    tags, ok := ctx.Request.Query.GetAll("tag")

    // tags == nil
    // ok == false

    if !ok {
        return <p>No tags selected.</p>
    }

    return <ul>
        <:for tag range={{ tags }}>
            <li>{{ tag }}</li>
        </:for>
    </ul>
}

The returned slice is a separate copy. Modifying it does not change the original parameters of the request.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?tag=go&tag=web

    tags, ok := ctx.Request.Query.GetAll("tag")

    if !ok {
        return <p>No tags selected.</p>
    }

    tags[0] = "modified"

    original, _ := ctx.Request.Query.Get("tag")

    // original == "go"
    return <p>{{ original }}</p>
}

Has()

It indicates if there is a parameter with at least one value.

Firma:func (Query) Has(key string) bool

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?featured=true

    featured := ctx.Request.Query.Has("featured")

    // featured == true
    return <p>Featured: {{ featured }}</p>
}

Has() is useful when you only need to check the existence of a parameter and do not need to check its value.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?debug=true

    if ctx.Request.Query.Has("debug") {
        return <p>Debug mode enabled.</p>
    }

    return <p>Debug mode disabled.</p>
}

When you also need the value, use it directly Get() to avoid consulting the collection twice.

gox
func GET(ctx *gox.Context) gox.Page {
    page, ok := ctx.Request.Query.Get("page")

    if !ok {
        page = "1"
    }

    return <p>Page {{ page }}</p>
}

IsEmpty()

It indicates whether the collection does not contain parameters with values.

Firma:func (Query) IsEmpty() bool

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products

    if ctx.Request.Query.IsEmpty() {
        return <p>No query parameters were provided.</p>
    }

    return <p>The request contains query parameters.</p>
}

A URL without a query string produces an empty collection.

text
/products

A URL with parameters produces a non-empty collection.

text
/products?page=2

Count()

Returns the amount of different parameters that contain at least one value.

Firma:func (Query) Count() int

Count() key account, not the total amount of values.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?category=books&tag=go&tag=web

    count := ctx.Request.Query.Count()

    // count == 2
    //
    // Claves:
    // category
    // tag
    return <p>Parameters: {{ count }}</p>
}

Although tag appears twice, represents a single key within the collection.

text
category = ["books"]
tag      = ["go", "web"]

Keys()

Returns the names of all parameters that contain at least one value.

Firma:func (Query) Keys() []string

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?sort=price&category=books&page=2

    keys := ctx.Request.Query.Keys()

    // keys contiene:
    // "category"
    // "page"
    // "sort"
    return <ul>
        <:for key range={{ keys }}>
            <li>{{ key }}</li>
        </:for>
    </ul>
}

Each key appears only once, even when the parameter contains several values.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?tag=go&tag=web&tag=backend

    keys := ctx.Request.Query.Keys()

    // keys == []string{"tag"}
    return <p>Parameters: {{ len(keys) }}</p>
}

The returned slice is a separate copy and can be modified without altering the request parameters.


Values()

Returns all values stored in the collection.

Firma:func (Query) Values() []string

The repeated parameter values are individually included in the result.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?page=2&tag=go&tag=web

    values := ctx.Request.Query.Values()

    // values contiene:
    // "2"
    // "go"
    // "web"
    return <ul>
        <:for value range={{ values }}>
            <li>{{ value }}</li>
        </:for>
    </ul>
}

Values() only returns the values. It does not retain the relationship between each value and its key.

When you need to know the name of each parameter, use Entries().

gox
func GET(ctx *gox.Context) gox.Page {
    values := ctx.Request.Query.Values()

    if len(values) == 0 {
        return <p>No query values were provided.</p>
    }

    return <p>Values: {{ len(values) }}</p>
}

The returned slice is a separate copy. Modifying it does not change the request parameters.


Entries()

Returns all parameters and their values as a map.

Firma:func (Query) Entries() map[string][]string

Each map key represents the name of a parameter and contains all its associated values.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?page=2&tag=go&tag=web

    entries := ctx.Request.Query.Entries()

    // entries["page"] == []string{"2"}
    // entries["tag"]  == []string{"go", "web"}
    return <ul>
        <:for tag range={{ entries["tag"] }}>
            <li>{{ tag }}</li>
        </:for>
    </ul>
}

You can visit all the entries in the collection:

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /products?category=books&sort=price&page=2

    entries := ctx.Request.Query.Entries()

    return <ul>
        <:for key, values range={{ entries }}>
            <li>
                <strong>{{ key }}</strong>

                <ul>
                    <:for value range={{ values }}>
                        <li>{{ value }}</li>
                    </:for>
                </ul>
            </li>
        </:for>
    </ul>
}

Both the map and its slices are independent copies. Modifying them does not change the original parameters of the request.

gox
func GET(ctx *gox.Context) gox.Page {
    // URL:
    // /articles?tag=go&tag=web

    entries := ctx.Request.Query.Entries()

    entries["tag"][0] = "modified"
    entries["page"] = []string{"3"}

    tag, _ := ctx.Request.Query.Get("tag")
    hasPage := ctx.Request.Query.Has("page")

    // tag == "go"
    // hasPage == false
    return <p>{{ tag }}</p>
}

Full example

The following example uses query parameters to implement a search with filters, tags, ordering and paging.

gox
func GET(ctx *gox.Context) gox.Page {
    // Ejemplo:
    // /products?search=laptop&category=electronics&tag=portable&tag=work&sort=price&page=2

    search, _ := ctx.Request.Query.Get("search")
    category, _ := ctx.Request.Query.Get("category")
    tags, hasTags := ctx.Request.Query.GetAll("tag")
    sort, hasSort := ctx.Request.Query.Get("sort")
    page, hasPage := ctx.Request.Query.Get("page")

    if !hasSort {
        sort = "name"
    }

    if !hasPage {
        page = "1"
    }

    return <main>
        <h1>Products</h1>

        <dl>
            <dt>Search</dt>
            <dd>{{ search }}</dd>

            <dt>Category</dt>
            <dd>{{ category }}</dd>

            <dt>Sort</dt>
            <dd>{{ sort }}</dd>

            <dt>Page</dt>
            <dd>{{ page }}</dd>
        </dl>

        <h2>Tags</h2>

        <:if !hasTags>
            <p>No tags selected.</p>
        <:else>
            <ul>
                <:for tag range={{ tags }}>
                    <li>{{ tag }}</li>
                </:for>
            </ul>
        </:if>
    </main>
}

Empty parameters

The new signature of Get() allows to distinguish between an absent parameter and a present parameter whose value is an empty string.

For example:

text
/products?page=

produce:

gox
func GET(ctx *gox.Context) gox.Page {
    page, ok := ctx.Request.Query.Get("page")

    // page == ""
    // ok == true
    return <p>Page: {{ page }}</p>
}

Instead:

text
/products

produce:

gox
func GET(ctx *gox.Context) gox.Page {
    page, ok := ctx.Request.Query.Get("page")

    // page == ""
    // ok == false
    return <p>Page: {{ page }}</p>
}

This difference makes it possible to validate correctly if the client omitted a parameter or sent it explicitly without value.


Value encoding

The reference parameters are decoded before they are stored in ctx.Request.Query.

For example:

text
/search?q=hello%20world

can be consulted as:

gox
func GET(ctx *gox.Context) gox.Page {
    query, ok := ctx.Request.Query.Get("q")

    if !ok {
        return <p>No search provided.</p>
    }

    // query == "hello world"
    return <p>{{ query }}</p>
}

The special characters must be encoded correctly when building a URL.


Conversion of values

All values of ctx.Request.Query They're strings.

When you need to work with numbers, boolean, dates or other types, you must convert them and validate possible errors.

gox
func GET(ctx *gox.Context) gox.Page {
    pageText, ok := ctx.Request.Query.Get("page")

    if !ok {
        pageText = "1"
    }

    page, err := strconv.Atoi(pageText)

    if err != nil || page < 1 {
        return <p>Invalid page.</p>
    }

    return <p>Page {{ page }}</p>
}

You must not assume that a value received from the URL contains the expected type or format.


Best practices

  • Use Get() when you only need the first value of a parameter.
  • Use GetAll() when a parameter can appear several times.
  • Check the boolean value returned by Get() and GetAll().
  • Use Has() when you only need to check for a parameter.
  • Define default values for optional parameters.
  • Always value the values before using them.
  • It explicitly converts numbers, booleans, dates and other types.
  • Rejects values that do not belong to the set permitted by the application.
  • It sets reasonable limits for parameters such as pages, quantities and sizes.
  • Do not build database queries by directly focusing URL values.
  • Do not use query parameters to send passwords, tokens or other confidential information.
  • It uses clear, stable and consistent parameter names.
  • Use Values() when you only need to go through all the values.
  • Use Entries() when you need to keep the relationship between the keys and their values.

To learn more about RequestSee your documentation. To learn more about URLSee your documentation. To learn more about FormSee your documentation. To learn more about RouteSee your documentation. To learn more about Context, check your documentation.


See also

Next step

Continue with Form to learn how to consult the fields sent through forms.

Form