webutil

package module
v2.2.1 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2023 License: MIT Imports: 16 Imported by: 0

README

webutil

webutil is a collection of utility functions to aid in the development of web applications in Go. this builds on top of some packages provided by the Gorilla web toolkit such as gorilla/schema and gorilla/sessions.

This package provides the ability to easily handle form validation, file uploads, serving different content types, and flashing of form data between requests.

Examples

Form Validation

Form validations is achieved via the webutil.Form and webutil.Validator interfaces. The webutil.Form interface wraps the Fields method that returns a map of the underlying fields in the form. The webutil.Validator interface wraps the Validate method for validating data. Below is an example of these interfaces being implemented for form validation,

type LoginForm struct {
    Email    string
    Password string
}

func (f LoginForm) Fields() map[string]string {
    return map[string]string{
        "email": f.Email,
    }
}

type LoginValidator struct {
    Form Login
}

func (v LoginValidator) Validate(errs webutil.ValidationErrors) error {
    if f.Email == "" {
        errs.Add("email", webutil.ErrFieldRequired("email"))
    }
    if f.Password == "" {
        errs.Add("password", webutil.ErrFieldRequired("password"))
    }
}

with the above implementation we can then use webutil.UnmarshalForm and webutil.Validate to unmarshal and validate the form data,

func Login(w http.ResponseWriter, r *http.Request) {
    var f LoginForm

    if err := webutil.UnmarshalForm(&f, r); err != nil {
        io.WriteString(w, err.Error())
        return
    }

    v := LoginValidator{
        Form: f,
    }

    if err := webutil.Validate(v); err != nil {
        io.WriteString(w, err.Error())
        return
    }
}

webutil.Validate will always return the webutil.ValidationErrors error type. Under the hood the gorilla/schema package is used to handle the unmarshalling of request data into a form.

File Uploads

File uploads can be handled via the webutil.File type. This can be used along the webutil.FileValidator to handle the uploading and validating of files,

type UploadForm struct {
    File *webutil.File
    Name string
}

func Upload(w http.ResponseWriter, r *http.Request) {
    f := UploadForm{
        File: &webutil.File{
            Field: "avatar",
        },
    }

    if err := webutil.UnmarshalFormWithFile(&f, f.File, r); err != nil {
        io.WriteString(w, err.Error())
        return
    }

    defer f.File.Remove()

    v := &webutil.FileValidator{
        File: f.File,
        Size: 5 * (1 << 20),
    }

    if err := webutil.Validate(v); err != nil {
        io.WriteString(w, err.Error())
        return
    }

    dir, _ := os.Getwd()
    dst, _ := os.CreateTemp(dir, "")

    io.Copy(dst, f.File)

    w.WriteHeader(http.StatusNoContent)
}

with the above example, we call the webutil.UnmarshalFormWithFile function to handle the unmarshalling of the file from the request. This will also handle requests where the file is sent as the request body itself, when this is done the URL query parameters are used as the typical form values. Validation of the file is then handled with the webutil.FileValidator.

Response Types

HTML, Text, and JSON response types can be sent using the respective functions provided by this package. These functions will set the appropriate Content-Type header, and Content-Length too.

func HTMLHandler(w http.ResponseWriter, r *http.Request) {
    webutil.HTML(w, "<h1>HTML response</h1>", http.StatusOK)
}

func TextHandler(w http.ResponseWriter, r *http.Request) {
    webutil.Text(w, "Text response", http.StatusOK)
}

func JSONHandler(w http.ResponseWriter, r *http.Request) {
    data := map[string]string{
        "message": "JSON response",
    }
    webutil.JSON(w, data, http.StatusOK)
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrFieldRequired = errors.New("field required")
	ErrFieldExists   = errors.New("already exists")
)

Functions

func BaseAddress

func BaseAddress(r *http.Request) string

BaseAddress will return the HTTP address for the given Request. This will return the Scheme of the current Request (http, or https), concatenated with the host. If the X-Forwarded-Proto, and X-Forwarded-Host headers are present in the Request, then they will be used for the Scheme and Host respectively.

func BasePath

func BasePath(path string) string

BasePath returns the last element of the given path. This will split the path using the "/" spearator. If the path is empty BasePath returns "/".

func FieldRequired added in v2.2.0

func FieldRequired(ctx context.Context, val any) error

FieldRequired checks to see if the given val was actually given. This only checks if val is a string, or has the String method on it, otherwise nil is returned.

func FlashFormWithErrors added in v2.1.0

func FlashFormWithErrors(sess *sessions.Session, f Form, errs ValidationErrors)

FlashFormWithErrors flashes the given Form and Errors to the given session under the "form_fields" and "form_errors" keys respectively.

func FormFields

func FormFields(sess *sessions.Session) map[string]string

FormField returns the map of form fields that has been flashed to the given session under the "form_fields" key. If the key does not exist, then an empty map is returned instead.

func HTML

func HTML(w http.ResponseWriter, content string, status int)

HTML sets the Content-Type of the given ResponseWriter to text/html, and writes the given content with the given status code to the writer. This will also set the Content-Length header to the len of content.

func JSON

func JSON(w http.ResponseWriter, data interface{}, status int)

JSON sets the Content-Type of the given ResponseWriter to application/json, and encodes the given interface to JSON to the given writer, with the given status code. This will also set the Content-Length header to the len of the JSON encoded data.

func Text

func Text(w http.ResponseWriter, content string, status int)

Text sets the Content-Type of the given ResponseWriter to text/plain, and writes the given content with the given status code to the writer. This will also se the Content-Length header to the len of content.

func UnmarshalForm

func UnmarshalForm(f Form, r *http.Request) error

UnmarshalForm parses the request into the given Form. If any errors occur during unmarshalling, then these will be returned via the ValidationErrors type.

func UnmarshalFormAndValidate

func UnmarshalFormAndValidate(f Form, r *http.Request) error

UnmarshalFormAndValidate parses the request into the given Form. If unmmarshalling succeeds, then the Form is validated via the Validate method.

func WrapFieldError added in v2.2.0

func WrapFieldError(name string, err error) error

WrapFieldError wraps the given error with the *FieldError type and returns it.

Types

type FieldError

type FieldError struct {
	Name string
	Err  error
}

FieldError captures an error and the field name that caused it.

func (*FieldError) Error

func (e *FieldError) Error() string

func (*FieldError) Unwrap

func (e *FieldError) Unwrap() error

Unwrap returns the underlying error.

type File

type File struct {
	// The underlying file that was uploaded.
	multipart.File

	// Header is the header of the file being uploaded.
	Header *multipart.FileHeader

	// Type is the MIME type of the file, this is set during the unmarshalling
	// of the file by sniffing the first 512 bytes of the file.
	Type string
}

File is used for unmarshalling files from requests.

func UnmarshalFile

func UnmarshalFile(field string, r *http.Request) (*File, bool, error)

UnmarshalFile parses the request for a file sent with it. If the request has the Content-Type of multipart/form-data, then the file will be taken from the multipart form via the given field, otherwise it will be taken from the request body. A boolean is returned for whether or not a file was sent in the request.

func UnmarshalFiles

func UnmarshalFiles(field string, r *http.Request) ([]*File, bool, error)

UnmarshalFiles parses the request for every file sent with it. The request must have the Content-Type of multipart/form-data, otherwise an error is returned. A boolean is returned for whether or not any files were sent in the request.

func UnmarshalFormWithFile

func UnmarshalFormWithFile(f Form, field string, r *http.Request) (*File, bool, error)

UnmarshalFormWithFile parses the request for a file sent with it. If the request has the Content-Type of multipart/form-data, then the file will be taken from the multipart form via the given field. This will then unmarshal the rest of the request data into the given Form. If file in the request was sent in the request body, then the URL query parameters are unmarshalled into the given Form. A boolean is returned for whether or not a file was a file in the request.

func UnmarshalFormWithFiles

func UnmarshalFormWithFiles(f Form, field string, r *http.Request) ([]*File, bool, error)

UnmarshalFormWithFiles parses the request for every file sent with it. The request must have the Content-Type of multipart/form-data, otherwise an error is returned. This will then unmarshal the rest of the request data into the given Form. A boolean is returned for whether or not any files were sent in the request.

func (*File) HasFile

func (f *File) HasFile() bool

func (*File) Remove

func (f *File) Remove() error

Remove will remove the underlying file if it was written to disk during the upload. This will typically only be done if the file was too large to store in memory.

type Form

type Form interface {
	// Fields returns a map of all the form's underlying values.
	Fields() map[string]string

	// Validate validates the form. This should return an error type of
	// ValidationErrors should validation fail.
	Validate(ctx context.Context) error
}

Form is the interface used for unmarhsalling and validating form data sent in an HTTP request.

type MatchError added in v2.2.0

type MatchError struct {
	Regexp *regexp.Regexp
}

func (MatchError) Error added in v2.2.0

func (e MatchError) Error() string

type ValidationErrors

type ValidationErrors map[string][]string

ValidationErrors records any validation errors that may have occurred. Each error is kept beneath the field for which the error occurred.

func FormErrors

func FormErrors(sess *sessions.Session) ValidationErrors

FormErrors returns the Errors that has been flashed to the given session under the "form_errors" key. If the key does not exist, then an empty Errors is returned instead.

func (ValidationErrors) Add

func (e ValidationErrors) Add(field string, err error)

Add adds the given error for the given field.

func (ValidationErrors) Err

func (e ValidationErrors) Err() error

func (ValidationErrors) Error

func (e ValidationErrors) Error() string

Error returns the string representation of the current set of errors. It will be formatted like so,

field:
    err
    err

func (ValidationErrors) First

func (e ValidationErrors) First(field string) string

First returns the first error message for the given field if any.

type Validator added in v2.2.0

type Validator struct {
	// contains filtered or unexported fields
}

Validator is the type used for validating data.

func (*Validator) Add added in v2.2.0

func (v *Validator) Add(name string, val any, fn ValidatorFunc)

Add will add a ValidatorFunc to the given Validator for the field of name and with the value of val.

func (*Validator) Validate added in v2.2.0

func (v *Validator) Validate(ctx context.Context) ValidationErrors

Validate runs the validatio functions and returns all errors via ValidationErrors. When calling this, a subsequent call to Err should be made on the returned ValidationErrors, this will either return an error or nil depending on whether or not ValidationErrors contains errors.

func (*Validator) WrapError added in v2.2.0

func (v *Validator) WrapError(wraps ...WrapErrorFunc)

WrapError sets the chain of WrapErrorFuncs to use when processing a validation error.

type ValidatorFunc added in v2.2.0

type ValidatorFunc func(ctx context.Context, val any) error

ValidatorFunc is the function type for validating a value in a form. This will return an error should validation fail.

func FieldEquals added in v2.2.0

func FieldEquals(expected any) ValidatorFunc

FieldEquals checks to see if the given val matches expected.

func FieldLen added in v2.2.0

func FieldLen(min, max int) ValidatorFunc

FieldLen checks to see if the given val is between the length of min and max.

func FieldMatches added in v2.2.0

func FieldMatches(re *regexp.Regexp) ValidatorFunc

FieldMatches checks to see if the given val matches the regular expression of re. This will return an error of type MatchError if validation fails.

func FieldMaxLen added in v2.2.0

func FieldMaxLen(max int) ValidatorFunc

FieldMaxLen checks to see if the given val is at least shorter than max.

func FieldMinLen added in v2.2.0

func FieldMinLen(min int) ValidatorFunc

FieldMinLen checks to see if the given val is at least longer than min.

type WrapErrorFunc added in v2.2.0

type WrapErrorFunc func(name string, err error) error

WrapErrorFunc is the function type for wrapping an error that is returned from a failed validation. This would be given the name of the field and the error for that failed validation. This would be used for either adding additional context to an error, or mutating it.

func IgnoreError added in v2.2.0

func IgnoreError(name string, target error) WrapErrorFunc

IgnoreError will return nil if the underlying validation error and field name match what is given as name and target. This is useful if there are benign errors you want to ignore during validation.

func MapError added in v2.2.0

func MapError(from, to error) WrapErrorFunc

MapError will map the given error from to the given error of to if the underlying error is of the type from. The underlying check is done via errors.Is.

Jump to

Keyboard shortcuts

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