Pages

A page in GOX is defined by a Go function that returns a value gox.Page.

These functions represent the HTTP input points of a file .gox located within the directory pages/.

gox
module index

import "github.com/gox-lang/gox"

func GET(ctx *gox.Context) gox.Page {
    return <h1>Hola GOX</h1>
}

Each function receives a *gox.Contextwhich provides access to the current request and the execution environment of the page.


Signature

All pages should be declared using the following signature.

gox
func <METHOD>(ctx *gox.Context) gox.Page

The function name determines the HTTP method to which the page will respond.

The parameter ctx must be of type *gox.Context and the function must return a gox.Page.


HTTP methods

GOX does not introduce own HTTP methods. The pages directly use the methods supported by the native Go HTTP server.

To respond to a method, a function whose name exactly matches the corresponding HTTP method must be declared.

gox
func GET(ctx *gox.Context) gox.Page {
    return <h1>Usuarios</h1>
}

func POST(ctx *gox.Context) gox.Page {
    return <p>Usuario recibido</p>
}

The methods available for an application can be enabled or restricted from the server configuration.

See Server Configuration for more information.


Naming convention

The functions that represent HTTP methods should be written using exactly the name of the method and always completely in capital letters.

gox
func GET(ctx *gox.Context) gox.Page

The following statements are invalid.

gox
func Get(ctx *gox.Context) gox.Page
gox
func get(ctx *gox.Context) gox.Page

GOX does not recognize declared functions using another name convention.


Main file

The functions that return gox.Page must always be declared in the main file of the page.

They cannot be defined in an imported module.

text
pages/
└── users.gox
gox
module users

import "github.com/gox-lang/gox"

func GET(ctx *gox.Context) gox.Page {
    return <h1>Usuarios</h1>
}

The auxiliary functions, components, types and any other logic can be organized in independent modules and imported normally.

However, the functions that represent HTTP methods must remain in the file .gox corresponding so that GOX can identify them during the compilation.

The location of the file within the directory pages/ also automatically determines the URL of the page.

See Routing to know how GOX builds the routes of an application.


Context

All pages receive a *gox.Context.

gox
func GET(ctx *gox.Context) gox.Page {

    ip := ctx.Request.IP()

    return <h1>{{ ip }}</h1>
}

The context provides access to the HTTP request, HTTP response and the page execution environment.

Through ctx it is possible to access objects like Request and Response, in addition to other server features.

The full documentation of gox.Context, its properties and methods are found in Request Context.


Return values

Although the signature of a page uses gox.Page, a page can return different types of values.

gox
func GET(ctx *gox.Context) gox.Page {
    return <h1>Hola GOX</h1>
}

You can also return text.

gox
func GET(ctx *gox.Context) gox.Page {
    return "Hola GOX"
}

Boolean numbers and values.

gox
func GET(ctx *gox.Context) gox.Page {
    return 123456789
}
gox
func GET(ctx *gox.Context) gox.Page {
    return true
}

Structures, maps, arrays and slices.

gox
func GET(ctx *gox.Context) gox.Page {

    user := struct {
        Name string
        Age  int
    }{
        Name: "Juan",
        Age:  30,
    }

    return user
}

Streams

It can also return a io.Reader to transmit files or content as stream.

gox
func GET(ctx *gox.Context) gox.Page {

    file, err := os.Open("report.pdf")
    if err != nil {
        panic(err)
    }

    return file
}

GOX automatically transforms the returned value into the body of the HTTP response.

Files

It can also return a gox.File to send a file to the client.

gox
func GET(ctx *gox.Context) gox.Page {
    file, err := gox.NewFile(gox.FileConfig{
        Path: "report.pdf",
    })

    if err != nil {
        panic(err)
    }

    ctx.Response.Headers.Set(
        "Content-Disposition",
        `attachment; filename="report.pdf"`,
    )

    return file
}

GOX automatically uses file information to build the HTTP response and set the necessary headers.

Without the header Content-Disposition: attachment, the browser will try to open the file directly when its format is compatible.

The pages only allow the return of a gox.FileThe guy. []gox.File it is not supported, as browsers cannot download several files in a single HTTP response.

In the Actions it is possible to return []gox.Filewhere the client receives an object arrangement File. Check the documentation of Actions.

For more information on file creation and handling, see the documentation of File.


Content-Type

The responses generated by a function gox.Page use by default:

text
text/html; charset=utf-8

This rule applies regardless of the type of returned value.

When the response represents another format, the page should explicitly establish the Content-Type by ctx.Response.Headers.

gox
module users

import "github.com/gox-lang/gox"

func GET(ctx *gox.Context) gox.Page {

    ctx.Response.Headers.Set(
        "Content-Type",
        "application/json; charset=utf-8",
    )

    return map[string]any{
        "name":   "Juan",
        "active": true,
    }
}

To return a PDF file.

gox
func GET(ctx *gox.Context) gox.Page {

    ctx.Response.Headers.Set(
        "Content-Type",
        "application/pdf",
    )

    file, err := os.Open("report.pdf")
    if err != nil {
        panic(err)
    }

    return file
}

GOX conserves the Content-Type set by the page and does not replace it with the default value.

The header configuration is part of the object Response.

See Request Context to know all available properties.


Response lifecycle

The properties of ctx.Response must be configured before starting to build the body of the response.

gox
func GET(ctx *gox.Context) gox.Page {

    ctx.Response.Headers.Set(
        "Content-Type",
        "application/json; charset=utf-8",
    )

    return map[string]any{
        "name":   "Juan",
        "active": true,
    }
}

When GOX starts processing the returned value and writes the first content in the body, the response is no longer modifiable.

From that time on, the following may not be amended:

  • The headers.
  • The status code.
  • Cookies.
  • The redirections.
  • Any other property of ctx.Response.

Attempting to modify the response after the body's construction began makes an error during the execution.

All these operations are carried out by ctx.Response.

See Request Context to know the full API.


Components

The components used within the temperate are part of the construction of the response body.

For this reason, a component should not change ctx.Response.

gox
func UserCard(ctx *gox.Context) gox.Component {

    // Incorrecto: el componente puede ejecutarse después de que
    // comenzó la construcción del cuerpo.
    ctx.Response.Headers.Set("X-Component", "UserCard")

    return <article>...</article>
}

The headers and the rest of the response configuration should be established in the function gox.Pagebefore you return the template.

gox
func GET(ctx *gox.Context) gox.Page {

    ctx.Response.Headers.Set("X-Page", "Users")

    return <main>
        <UserCard />
    </main>
}

The components should be limited to building content and not dependent on the possibility of modifying the HTTP response.


Integration with Go

The pages are normal Go functions and take direct advantage of the language characteristics.

You can use variables, functions, control structures, interfaces, application-defined types and any other Go feature to build a response.

gox
func GET(ctx *gox.Context) gox.Page {

    title := "Información de la solicitud"

    if title == "" {
        title = "GOX"
    }

    return <main>
        <h1>{{ title }}</h1>
    </main>
}

The pages can also reuse components to divide the interface into smaller and reusable parts.

See Components to learn how to build modular interfaces.

GOX uses the signature of these functions and their location within the directory pages/ to automatically integrate them with the HTTP life cycle of the application.


Best practices

  • Keep the configuration of ctx.Response at the beginning of the function, before return.
  • It uses components to build the interface, not to modify the HTTP response.
  • Organizes business logic in independent modules when it can be reused.
  • Limit functions gox.Page to coordinate the request and build the response.

To learn more about Page system, check your documentation.


See also

Next step

Continue with Context to learn how to access the request, response, session and other features available during the execution of a page.

Context