convreq

package module
v1.7.1 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2024 License: Apache-2.0 Imports: 10 Imported by: 12

README

convreq

GoDoc Build Status

Experimental project to make writing webservers more convenient.

The core principle of the library is that while the func(w http.ResponseWriter, r *http.Request) signature is very powerful, often a more convenient interface would be preferable.

Example usage

func main() {
	http.Handle("/", convreq.Wrap(homePageHandler))
	srv := &http.Server{
		Addr: ":8080",
	}
	log.Fatal(srv.ListenAndServe())
}

type homePageGet struct {
	Name string
}

type homePagePost struct {
	Password string
}

func homePageHandler(ctx context.Context, r *http.Request, get homePageGet, post *homePagePost) convreq.HttpResponse {
	if get.Name == "" {
		return respond.BadRequest("Who are you?")
	}
	if post != nil && post.Password == "secret" {
		return respond.Redirect(302, "/secrets/")
	}
	t, err := template.New("tpl").Parse("How do you do, {{.}}?")
	if err != nil {
		return respond.Error(err)
	}
	return respond.RenderTemplate(t, get.Name)
}

Signature

I propose a signature that:

  • passes a context directly (as the first parameter)
  • simplifies error handling by allowing a return value
  • passes in type casted input (GET+POST) to the request handler
  • defers responding until the function has returned so later errors can still be handled and you're not caught with errors halfway through your response

So I arrived at func MyHandler(ctx context.Context, r *http.Request, get MyHandlerGet, post *MyHandlerPost) convreq.HttpResponse.

get and post are structs defined by the application that hold input fields. github.com/gorilla/schema is used to decode the GET/POST values into these structs.

get also contains any URL parameters for github.com/gorilla/mux.

Dispatchers

I have implemented two different dispatchers: one with code generation, and one with reflect. Advantages of each:

  • The reflect dispatcher doesn't enforce an argument order. It looks at the types of each parameter and constructs the value required. This will be convenient for e.g. github.com/gorilla/sessions as handlers that require sessions can trivially add a parameter to receive a session.
  • The codegen dispatcher does enforce an argument order, thus promoting consistency.
  • The codegen dispatcher is most likely much faster as it does far less magic at runtime.
  • The codegen dispatcher will catch more problems at compile time. The reflect dispatcher tries its best to catch errors at initialization time, but some might only be noticed at request time.
  • The reflect dispatcher is easier to use, doesn't depend on go-generate or requiring the programmer to know when to regenerate.

Maybe I'll make the codegen dispatcher smarter to also allow for more freedom in method signature.

I'm considering to keep both dispatchers, encourage the reflect dispatcher for development and the codegen dispatcher for prod deployments.

Responding

Rather than allowing the code to respond pieces whenever it wants, I enforce that all responding happens after returning from the request handler. An interface HttpResponse can be returned and one can implement it to do anything you want.

I'll implement a couple of basic responders:

  • Rendering errors easily. Setting the correct HTTP response code and optionally allowing to configure an error page renderer.
  • Template rendering. This should be as easy as return convreq.RenderTemplate(myTemplate, myData). This'll make it possible to automatically reload templates for development servers too.
  • Redirection is as easy as return convreq.Redirect(302, "/home").
  • Setting response headers.

This is not an officially supported Google product.

Documentation

Overview

Library convreq is a library to make HTTP requests more convenient.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ContextWithErrorHandler

func ContextWithErrorHandler(ctx context.Context, f ErrorHandler) context.Context

ContextWithErrorHandler returns a new context within which all errors are rendered with ErrorHandler.

func URL

func URL(r *mux.Route, strct interface{}) (*url.URL, error)

func Wrap

func Wrap(f interface{}, opts ...WrapOption) http.HandlerFunc

Wrap takes a request handler function and returns a http.HandlerFunc for use with net/http. The given handler is expected to take arguments like context.Context, *http.Request and return a convreq.HttpResponse or an error.

Types

type ErrorHandler

type ErrorHandler = internal.ErrorHandler

ErrorHandler is a callback type that you can register with ContextWithErrorHandler or WithErrorHandler to have your own callback called to render errors.

type HttpResponse

type HttpResponse = internal.HttpResponse

HttpResponse is what is to be returned from request handlers. Respond gets executed to write the response to the client.

type WrapOption

type WrapOption func(wo *wrapOptions)

WrapOption can be given to Wrap to modify behavior.

func WithContextWrapper

func WithContextWrapper(f func(ctx context.Context) (context.Context, func())) WrapOption

WithContextWrapper allows you to replace the context for the request. f is called just before the request gets handled, and the cancel function is called after the request is finished. The cancel function may be nil.

func WithErrorHandler

func WithErrorHandler(f ErrorHandler) WrapOption

WithErrorHandler can be passed on Wrap() to set an ErrorHandler for requests.

func WithParameterType

func WithParameterType(t reflect.Type, e extractor) WrapOption

WithParameterType makes Wrap() understand an extra type for request handler signatures. The extractor is a function that can derive the requested type from a ResponseWriter and Request.

func WithReturnType

func WithReturnType(t reflect.Type, f interface{}) WrapOption

WithReturnType makes Wrap() understand an extra return type for request handler signatures. You should pass in a function that takes `http.ResponseWriter, *http.Request, T` where T is the type you've passed in as t.

Directories

Path Synopsis
cmd
Library genapi provides an internal API only to be used by code generated by convreq.
Library genapi provides an internal API only to be used by code generated by convreq.
Library respond creates convreq.HttpResponse objects.
Library respond creates convreq.HttpResponse objects.

Jump to

Keyboard shortcuts

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