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/.
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.
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.
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.
func GET(ctx *gox.Context) gox.Page The following statements are invalid.
func Get(ctx *gox.Context) gox.Page 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.
pages/
└── users.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.
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.
func GET(ctx *gox.Context) gox.Page {
return <h1>Hola GOX</h1>
} You can also return text.
func GET(ctx *gox.Context) gox.Page {
return "Hola GOX"
} Boolean numbers and values.
func GET(ctx *gox.Context) gox.Page {
return 123456789
} func GET(ctx *gox.Context) gox.Page {
return true
} Structures, maps, arrays and slices.
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.
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.
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/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.
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.
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.
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.
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.
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.
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.Responseat the beginning of the function, beforereturn. - 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.Pageto coordinate the request and build the response.
To learn more about Page system, check your documentation.