bind

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jan 2, 2024 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package bind contains model binding features to be used along *lit.Request.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrUnsupportedContentType = errors.New("unsupported Content-Type")

Functions

func Body

func Body[T any](r *lit.Request) (T, error)

Body binds the request's body into the fields of a struct of type T.

It checks the Content-Type header to select an appropriated parsing method:

  • "application/json" for JSON parsing
  • "application/xml" or "text/xml" for XML parsing
  • "application/x-yaml" for YAML parsing
  • "application/x-www-form-urlencoded" for form parsing

Tags from encoding packages, such as "json", "xml" and "yaml" tags, can be used appropriately. For form parsing, use the tag "form".

If the Content-Type header is not set, Body defaults to JSON parsing. If it is not supported, it returns ErrUnsupportedContentType.

If *T implements validate.Validatable (with a pointer receiver), Body calls validate.Fields on the result and can return validate.Error.

If T is not a struct type, Body panics.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	req := httptest.NewRequest(http.MethodPost, "/books", strings.NewReader(`
		{"name": "Percy Jackson", "publishYear": 2009}
	`))

	r := lit.NewRequest(req)

	type RequestBody struct {
		Name        string `json:"name"`
		PublishYear int    `json:"publishYear"`
	}

	body, err := bind.Body[RequestBody](r)
	if err == nil {
		fmt.Println(body.Name)
		fmt.Println(body.PublishYear)
	}

}
Output:
Percy Jackson
2009
func Header[T any](r *lit.Request) (T, error)

Header binds the request's header into the fields of a struct of type T. Targeted fields should be exported and annotated with the tag "header" (case-insensitive). Otherwise, they are ignored.

If any field couldn't be bound, Header returns Error.

If *T implements validate.Validatable (with a pointer receiver), Header calls validate.Fields on the result and can return validate.Error.

If T is not a struct type, Header panics.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	req := httptest.NewRequest(http.MethodGet, "/books", nil)
	req.Header.Add("Content-Length", "150")
	req.Header.Add("Authorization", "Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH")

	r := lit.NewRequest(req)

	type Header struct {
		ContentLength uint   `header:"Content-Length"`
		Authorization string `header:"Authorization"`
	}

	h, err := bind.Header[Header](r)
	if err == nil {
		fmt.Println(h.ContentLength)
		fmt.Println(h.Authorization)
	}

}
Output:
150
Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH

func HeaderField

func HeaderField[T primitiveType | time.Time](r *lit.Request, header string) (T, error)

HeaderField binds a field from the request's header into a value of type T. T can be either a primitive type or a time.Time.

HeaderField consider header as case-insensitive.

If the value can't be bound into T, HeaderField returns Error.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	req := httptest.NewRequest(http.MethodGet, "/books", nil)
	req.Header.Add("Content-Length", "150")
	req.Header.Add("Authorization", "Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH")

	r := lit.NewRequest(req)

	contentLength, err := bind.HeaderField[int](r, "Content-Length")
	if err == nil {
		fmt.Println(contentLength)
	}

	authorization, err := bind.HeaderField[string](r, "authorization") // case-insensitive
	if err == nil {
		fmt.Println(authorization)
	}

}
Output:
150
Bearer uPSsoa65gqkFv2Z6sZ3rZCZwnCjzaXe8TNdk0bJCFFJGrH6wmnzyK4evHBtTuvVH

func Query

func Query[T any](r *lit.Request) (T, error)

Query binds the request's query parameters into the fields of a struct of type T. Targeted fields should be exported and annotated with the tag "query". Otherwise, they are ignored.

If a field can't be bound, Query returns Error.

If *T implements validate.Validatable (with a pointer receiver), Query calls validate.Fields on the result and can return validate.Error.

If T is not a struct type, Query panics.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	req := httptest.NewRequest(http.MethodGet, "/books", nil)
	req.URL.RawQuery = "publish_year=2009&name=Percy%20Jackson"

	r := lit.NewRequest(req)

	type BookQuery struct {
		PublishYear uint   `query:"publish_year"`
		Name        string `query:"name"`
	}

	query, err := bind.Query[BookQuery](r)
	if err == nil {
		fmt.Println(query.PublishYear, query.Name)
	}

}
Output:
2009 Percy Jackson

func Request

func Request[T any](r *lit.Request) (T, error)

Request binds the request's body, query, header and URI parameters into the fields of a struct of type T. Targeted fields should be exported and annotated with corresponding binding tags. Otherwise, they are ignored.

It's an optimized combination of the binding functions Body, Query, Header and URIParameters, suitable when you need to read from multiple inputs of the request.

If a field can't be bound, Request returns Error.

If *T implements validate.Validatable (with a pointer receiver), Request calls validate.Fields on the result and can return validate.Error.

If T is not a struct type, Request panics.

func URIParameter

func URIParameter[T primitiveType | time.Time](r *lit.Request, parameter string) (T, error)

URIParameter binds a request's URI parameter into a value of type T. T can be either a primitive type or a time.Time.

If the value can't be bound into T, URIParameter returns Error.

If parameter is not registered as one of the request's expected parameters, URIParameter panics.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	r := lit.NewRequest(
		httptest.NewRequest(http.MethodGet, "/users/123/books/book_1", nil),
	).WithURIParameters(
		map[string]string{"user_id": "123", "book_id": "book_1"},
	)

	userID, err := bind.URIParameter[int](r, "user_id")
	if err == nil {
		fmt.Println(userID)
	}

}
Output:
123

func URIParameters

func URIParameters[T any](r *lit.Request) (T, error)

URIParameters binds the request's URI parameters into the fields of a struct of type T. Targeted fields should be exported and annotated with the tag "uri". Otherwise, they are ignored.

If a field can't be bound, URIParameters returns Error.

If *T implements validate.Validatable (with a pointer receiver), URIParameters calls validate.Fields on the result and can return validate.Error.

If T is not a struct type, URIParameters panics.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/jvcoutinho/lit"
	"github.com/jvcoutinho/lit/bind"
)

func main() {
	r := lit.NewRequest(
		httptest.NewRequest(http.MethodGet, "/users/123/books/book_1", nil),
	).WithURIParameters(
		map[string]string{"user_id": "123", "book_id": "book_1"},
	)

	type RequestURIParameters struct {
		UserID int    `uri:"user_id"`
		BookID string `uri:"book_id"`
	}

	uri, err := bind.URIParameters[RequestURIParameters](r)
	if err == nil {
		fmt.Println(uri.UserID, uri.BookID)
	}

}
Output:
123 book_1

Types

type Error

type Error struct {
	// Incoming value.
	Value string
	// Target of the binding.
	Target reflect.Type
	// The actual error.
	Err error
}

Error is returned when a binding to a target value fails.

func (Error) Error

func (e Error) Error() string

Jump to

Keyboard shortcuts

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