genhttp

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2024 License: MIT Imports: 4 Imported by: 0

README

genhttp

genhttp provides a generics-powered HTTP microframework for handling requests.

The genhttp microframework is really a small pattern around request handling. The pattern is that a request will be parsed, then validated, then executed. This is represented in code by making each endpoint a type, and giving them a ParseRequest, ValidateRequest, and ExecuteRequest method. A Handle helper function calls these functions in order, checking for errors in between and short-circuiting when they're found. Thanks to generics, these methods can operate on an endpoint-specific request type that gets created by the ParseRequest method and passed directly into subsequent methods.

This pattern is useful for doing unit testing, as it separates the three responsibilities of an HTTP endpoint into discrete functions and makes them accessible through a more constrained interface than an http.Request and a more easily-examined interface than an http.ResponseWriter. Rather than reducing requests and responses to byte slices, they can be handled as structured Go types.

Documentation

Overview

Package genhttp provides a generics-powered HTTP microframework for handling requests.

The genhttp microframework is really a small pattern around request handling. The pattern is that a request will be parsed, then validated, then executed. This is represented in code by making each endpoint a type, and giving them a `ParseRequest`, `ValidateRequest`, and `ExecuteRequest` method. A `Handle` helper function calls these functions in order, checking for errors in between and short-circuiting when they're found. Thanks to generics, these methods can operate on an endpoint-specific request type that gets created by the `ParseRequest` method and passed directly into subsequent methods.

This pattern is useful for doing unit testing, as it separates the three responsibilities of an HTTP endpoint into discrete functions and makes them accessible through a more constrained interface than an `http.Request` and a more easily-examined interface than an `http.ResponseWriter`. Rather than reducing requests and responses to byte slices, they can be handled as structured Go types.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Handle

func Handle[Request any, Response Responder](respCreator ResponseCreator[Response], handler Handler[Request, Response]) http.Handler

Handle provides an http.Handler that will call the passed Handler. `rf` is used to create a new instance of the Response type. Then the `ParseRequest` method of `h` will be called, followed by `ValidateRequest` and `ExecuteRequest`. At the end, the Response has its `Send` method called.

If at any point in this process the Response's `HasErrors` method returns `true`, the Response's `Send` method is called and the function returns.

Types

type CookieWriter added in v0.2.0

type CookieWriter interface {
	// WriteCookies returns the cookies to write. An attempt is always made
	// to write cookies.
	WriteCookies() []*http.Cookie
}

CookieWriter is an interface describing a Responder that sometimes responds by writing cookies to the client.

type Handler

type Handler[Request any, Response Responder] interface {
	// ParseRequest turns an `http.Request` into the Request type passed
	// in, usually by parsing some encoding. The returned context.Context
	// will be used as the new request context; if in doubt, return the
	// context.Context passed as an argument.
	ParseRequest(context.Context, *http.Request, Response) (Request, context.Context)

	// ValidateRequest checks that the passed Request is valid, for
	// whatever definition of valid suits the endpoint. The returned
	// context.Context will be used as the new request context; if in
	// doubt, return the context.Context passed as an argument.
	ValidateRequest(context.Context, Request, Response) context.Context

	// ExecuteRequest performs the action described by the Request. It can
	// assume that the Request is valid. The returned context.Context will
	// be used as the new request context; if in doubt, return the
	// context.Context passed as an argument.
	ExecuteRequest(context.Context, Request, Response) context.Context
}

Handler is an endpoint that is going to parse, validate, and execute an HTTP request. Its Request type parameter should be a type that can describe the request, usually a struct with JSON tags or something similar. The Response type parameter should be an implementation of the Responder interface, usually a pointer that can be modified in the ParseRequest, ValidateRequest, and ExecuteRequest methods.

type Redirecter added in v0.2.0

type Redirecter interface {
	// RedirectTo returns the URL to redirect to and the HTTP status code
	// to use when redirecting. If the status code returned is between 300
	// and 399, inclusive, genhttp will call http.Redirect with the
	// returned URL and status code instead of calling Send.
	RedirectTo() (url string, status int)
}

Redirecter is an interface describing a Responder that sometimes responds by redirecting the client.

type Responder

type Responder interface {
	// HasErrors should return true if the response is considered an error
	// response and processing should not proceed.
	HasErrors() bool

	// Send writes the response to the http.ResponseWriter.
	Send(context.Context, http.ResponseWriter)

	// HandlePanic updates the Response in the face of a panic while
	// processing the request.
	HandlePanic(ctx context.Context, recoverArg any)
}

Responder is an interface describing a response type.

type ResponseCreator

type ResponseCreator[Response Responder] interface {
	NewResponse(context.Context, *http.Request) Response
}

ResponseCreator is a factory type that is capable of generating new Responder instances that are ready to be used.

We use a type parameter here instead of using the interface directly because we want the response types to be able to be structs with encoding tags or whatever, and to have their fields be directly accessible without a type assertion, which the Responder interface isn't able to provide.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL