Lifecycle

The life cycle of Response defines the period during which the HTTP response can be modified.

As a general rule, Response must be configured before return of a gox.Page or one gox.ActionDuring the generation of the temperate the response is no longer modifiable to ensure the consistency of the content sent to the client.

If you want to know all the APIs available to modify the response, see the documentation for Response.


What is the lifecycle?

Each HTTP request creates a new instance of ctx.Response.

During the execution of a gox.Page or one gox.Action It is possible to configure the status code, the headers, cookies and the other properties of the response.

However, once GOX begins to generate the template returned by the page or action, Response no longer modifiable.


When can Response be modified?

Response remains modifiable throughout the execution of a gox.Page or one gox.Actionuntil the return.

For this reason, the entire response configuration must be done before the result is returned.

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

	// Response es modificable.
	ctx.Response.Status.SetCode(200)
	ctx.Response.Headers.Set("Cache-Control", "no-cache")

	// Response se cierra para modificaciones.
	return <h1>Hola George</h1>
}

In this example all the configuration of Response occurs before return, so all operations are valid.


When can Response no longer be modified?

Response is no longer modifiable during the return of a gox.Page or one gox.Action.

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

	// Response es modificable.
	ctx.Response.Status.SetCode(200)

	// Response se cierra para modificaciones.
	return <>
		// Response ya no es modificable.
		<h1>Hola George</h1>
	</>
}

Once GOX begins to generate the template returned by the page or action, any attempt to modify Response It will make a mistake.


Common errors

Modify Response from a component

The components can be executed when Response It has already ceased to be modifiable.

gox
func IsLogin(ctx *gox.Context, user string) gox.Component {
	if !validate.IsLogin(ctx) {
		ctx.Response.DoneWith(403) // Error: Response ya no es modificable.
	}

	return <h1>Bienvenido {{ user }}</h1>
}

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

	// Response es modificable.
    name := "George"

	// Response se cierra para modificaciones.
	return <div>
        // Response ya no es modificable.
		<&IsLogin ctx={{ ctx }} name={{ name }}/>
	</div>
}

Although this code may seem correct, the component is run during the generation of the temperate, when Response It no longer supports any changes.

For this reason, it is not recommended to amend Response from components.


Modify Response from an expression

The same problem can occur within an expression used by the temperate.

goxx
func LoginClass(ctx *gox.Context) string {
	if !validate.IsLogin(ctx) {
		ctx.Response.Status.SetCode(403) // Error: Response ya no es modificable.
		return "fg-red"
	}

	return "fg-green"
}

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

	// Response es modificable.
    name := "George"

	// Response se cierra para modificaciones.
	return <h1 class={{ LoginClass(ctx) }}>
		Hola {{ name }}
	</h1>
}

Although the function is called from the temperate, its execution occurs during the generation of the response, when Response It can no longer be changed.


Modify Response from a deferred function

The functions recorded through defer are executed after the gox.Page or gox.Action sets its return value.

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

	// Response es modificable.

    defer func() {
		// Response ya no es modificable.
		ctx.Response.Headers.Set("Cache-Control", "no-cache")
	}()

	// Response es modificable.


	// Response se cierra para modificaciones.
	return <h1>Hola George</h1>
}

In this example, the deferred function tries to modify the headers after Response it has been closed for modifications, so the operation makes a mistake.

For this reason, it should not be amended. Response from functions performed by defer. Use these functions only for cleaning operations that do not alter the HTTP response.


What's the right way?

The entire configuration of Response should be done before return of a gox.Page or one gox.Action.

gox
func GET(ctx *gox.Context) gox.Page {
	if !validate.IsLogin(ctx) {
		ctx.Response.DoneWith(403)
	}

	ctx.Response.Headers.Set("Cache-Control", "no-cache")

	return <h1>Hola George</h1>
}

This pattern keeps all the response settings in one place, facilitates the reading of the code and avoids ambiguous behaviors.

If you need to finish an request immediately, check the documentation of DoneWith.


Best practices

  • Configure Response before return of a gox.Page or one gox.Action.
  • Keep the entire response configuration grouped at the beginning of the function.
  • Avoid changing Response from reusable components.
  • Avoid changing Response from functions performed as part of the temperate.
  • Avoid changing Response from functions performed by defer.
  • Use DoneWith() where the request is to be completed immediately.

See also

Next step

Continue with the documentation for Status to learn to set the HTTP status code of an response.

Status