chix

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 15, 2025 License: MIT Imports: 15 Imported by: 0

README

Chix

This package provides some methods that Chi lacks, such as binding and rendering.

A lot of the code in this package comes from Fiber, the last synchronized version: bc4c920ea6b36d2b9d0396853a640b8b043951b5.

Guides

Custom Encoders and Decoders

Chix supports custom JSON/XML encoders and decoders. Here's an example:

import (
    "encoding/json"
    "encoding/xml"

    "github.com/go-rat/chix"
)

func init() {
    chix.JSONEncoder = json.NewEncoder
    chix.JSONDecoder = json.NewDecoder
    chix.XMLEncoder = xml.NewEncoder
    chix.XMLDecoder = xml.NewDecoder
}
Binding
Support Binders
Binding into a Struct

Chix supports binding request data directly into a struct using gofiber/schema. Here's an example:

// Field names must start with an uppercase letter
type Person struct {
	Name string `json:"name" xml:"name" form:"name"`
	Pass string `json:"pass" xml:"pass" form:"pass"`
}

router.Post("/", func(w http.ResponseWriter, r *http.Request) {
	p := new(Person)
	bind := chix.NewBind(r)
	defer bind.Release()

	if err := bind.Body(p); err != nil {
		return err
	}

	log.Println(p.Name) // Output: john
	log.Println(p.Pass) // Output: doe

	// Additional logic...
})

// Run tests with the following curl commands:

// JSON
curl -X POST -H "Content-Type: application/json" --data "{\"name\":\"john\",\"pass\":\"doe\"}" localhost:3000

// XML
curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000

// URL-Encoded Form
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "name=john&pass=doe" localhost:3000

// Multipart Form
curl -X POST -F name=john -F pass=doe http://localhost:3000

// Query Parameters
curl -X POST "http://localhost:3000/?name=john&pass=doe"
Binding into a Map

Chix allows binding request data into a map[string]string or map[string][]string. Here's an example:

router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	params := make(map[string][]string)
	bind := chix.NewBind(r)
	defer bind.Release()

	if err := bind.Query(params); err != nil {
		return err
	}

	log.Println(params["name"])     // Output: [john]
	log.Println(params["pass"])     // Output: [doe]
	log.Println(params["products"]) // Output: [shoe hat]

	// Additional logic...
})

// Run tests with the following curl command:

curl "http://localhost:3000/?name=john&pass=doe&products=shoe&products=hat"
Render
Support Methods
  • ContentType
  • Status
  • Header
  • Cookie
  • WithoutCookie
  • Redirect
  • RedirectPermanent
  • PlainText
  • Data
  • HTML
  • JSON
  • JSONP
  • XML
  • NoContent
  • Stream
  • EventStream
  • SSEvent
  • File
  • Download
  • Flush
  • Hijack
  • Release
Set Content-Type
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.ContentType("application/json")
	// Your code...
})
Set Status Code
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.Status(http.StatusOK)
	// Your code...
})
Set Headers
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.Header("X-Custom-Header", "value")
	// Your code...
})
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.Cookie(&http.Cookie{
		Name:  "token",
		Value: "your-token",
	})
	// Your code...
})
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.WithoutCookie("token")
	// Your code...
})
Redirect
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
	render.Redirect("/new-location")
})
Permanent Redirect
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
	render.RedirectPermanent("/new-location")
})
Render Plain Text
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
 	defer render.Release()
 	render.PlainText("Hello, World!")
})
Render Raw Data
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.Data([]byte("Hello, World!"))
})
Render HTML
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.HTML("<h1>Hello, World!</h1>")
})
Render JSON
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.JSON(chix.M{
		"hello": "world",
	})
})
Render JSONP
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.JSONP("callback", chix.M{
		"hello": "world",
	})
})
Render XML
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
 
	type Person struct {
		Name string `xml:"name"`
		Age  int    `xml:"age"`
	}
 
	render.XML(Person{Name: "John", Age: 30})
})
Send No Content
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
	defer render.Release()
	render.NoContent()
})
Stream Response
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
	defer render.Release()
 
	clientDisconnected := render.Stream(func(w io.Writer) bool {
		_, _ = w.Write([]byte("chunk of data\n"))
		time.Sleep(100 * time.Millisecond)
		return true // continue streaming
	})
 
	if clientDisconnected {
		// Handle client disconnect
	}
})
Event Stream
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
 
	ch := make(chan map[string]string)
 
	// In another goroutine
	go func() {
		ch <- map[string]string{"message": "hello"}
		time.Sleep(time.Second)
		ch <- map[string]string{"message": "world"}
		close(ch)
	}()
 
	render.EventStream(ch)
})
Server-Sent Event
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)

	event := renderer.SSEvent{
		Event: "message",
		Data:  strings.NewReader("Hello, World!"),
		ID:    "1",
		Retry: 3000,
	}

	render.SSEvent(event)
})
Serve File
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
	render.File("path/to/file.txt")
})
Download File
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w, r)
	render.Download("path/to/file.txt", "download.txt")
})
Flush Buffer
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
 
	// Write some data
	w.Data([]byte("Some data"))
 
	// Flush immediately to client
	render.Flush()
 
	// Write more data later...
})
Hijack Connection
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
	render := chix.NewRender(w)
 
	hijacker, ok := render.Hijack()
	if !ok {
		// Hijacking not supported
		return
	}
 
	conn, bufrw, err := hijacker.Hijack()
	if err != nil {
		// Handle error
		return
	}
	defer conn.Close()
 
	// Use the hijacked connection
	bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n")
	bufrw.WriteString("Hello from hijacked connection")
	bufrw.Flush()
})

Documentation

Index

Constants

View Source
const (
	MIMETextXML         = "text/xml"
	MIMETextHTML        = "text/html"
	MIMETextPlain       = "text/plain"
	MIMETextJavaScript  = "text/javascript"
	MIMETextCSS         = "text/css"
	MIMEEventStream     = "text/event-stream"
	MIMEApplicationXML  = "application/xml"
	MIMEApplicationJSON = "application/json"
	// Deprecated: use MIMETextJavaScript instead
	MIMEApplicationJavaScript = "application/javascript"
	MIMEApplicationForm       = "application/x-www-form-urlencoded"
	MIMEOctetStream           = "application/octet-stream"
	MIMEMultipartForm         = "multipart/form-data"

	MIMETextXMLCharsetUTF8         = "text/xml; charset=utf-8"
	MIMETextHTMLCharsetUTF8        = "text/html; charset=utf-8"
	MIMETextPlainCharsetUTF8       = "text/plain; charset=utf-8"
	MIMETextJavaScriptCharsetUTF8  = "text/javascript; charset=utf-8"
	MIMETextCSSCharsetUTF8         = "text/css; charset=utf-8"
	MIMEEventStreamCharsetUTF8     = "text/event-stream; charset=utf-8"
	MIMEApplicationXMLCharsetUTF8  = "application/xml; charset=utf-8"
	MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
	// Deprecated: use MIMETextJavaScriptCharsetUTF8 instead
	MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8"
)

MIME types that are commonly used

View Source
const (
	HeaderAuthorization                      = "Authorization"
	HeaderProxyAuthenticate                  = "Proxy-Authenticate"
	HeaderProxyAuthorization                 = "Proxy-Authorization"
	HeaderWWWAuthenticate                    = "WWW-Authenticate"
	HeaderAge                                = "Age"
	HeaderCacheControl                       = "Cache-Control"
	HeaderClearSiteData                      = "Clear-Site-Data"
	HeaderExpires                            = "Expires"
	HeaderPragma                             = "Pragma"
	HeaderWarning                            = "Warning"
	HeaderAcceptCH                           = "Accept-CH"
	HeaderAcceptCHLifetime                   = "Accept-CH-Lifetime"
	HeaderContentDPR                         = "Content-DPR"
	HeaderDPR                                = "DPR"
	HeaderEarlyData                          = "Early-Data"
	HeaderSaveData                           = "Save-Data"
	HeaderViewportWidth                      = "Viewport-Width"
	HeaderWidth                              = "Width"
	HeaderETag                               = "ETag"
	HeaderIfMatch                            = "If-Match"
	HeaderIfModifiedSince                    = "If-Modified-Since"
	HeaderIfNoneMatch                        = "If-None-Match"
	HeaderIfUnmodifiedSince                  = "If-Unmodified-Since"
	HeaderLastModified                       = "Last-Modified"
	HeaderVary                               = "Vary"
	HeaderConnection                         = "Connection"
	HeaderKeepAlive                          = "Keep-Alive"
	HeaderAccept                             = "Accept"
	HeaderAcceptCharset                      = "Accept-Charset"
	HeaderAcceptEncoding                     = "Accept-Encoding"
	HeaderAcceptLanguage                     = "Accept-Language"
	HeaderCookie                             = "Cookie"
	HeaderExpect                             = "Expect"
	HeaderMaxForwards                        = "Max-Forwards"
	HeaderSetCookie                          = "Set-Cookie"
	HeaderAccessControlAllowCredentials      = "Access-Control-Allow-Credentials"
	HeaderAccessControlAllowHeaders          = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowMethods          = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowOrigin           = "Access-Control-Allow-Origin"
	HeaderAccessControlExposeHeaders         = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge                = "Access-Control-Max-Age"
	HeaderAccessControlRequestHeaders        = "Access-Control-Request-Headers"
	HeaderAccessControlRequestMethod         = "Access-Control-Request-Method"
	HeaderOrigin                             = "Origin"
	HeaderTimingAllowOrigin                  = "Timing-Allow-Origin"
	HeaderXPermittedCrossDomainPolicies      = "X-Permitted-Cross-Domain-Policies"
	HeaderDNT                                = "DNT"
	HeaderTk                                 = "Tk"
	HeaderContentDisposition                 = "Content-Disposition"
	HeaderContentEncoding                    = "Content-Encoding"
	HeaderContentLanguage                    = "Content-Language"
	HeaderContentLength                      = "Content-Length"
	HeaderContentLocation                    = "Content-Location"
	HeaderContentType                        = "Content-Type"
	HeaderForwarded                          = "Forwarded"
	HeaderVia                                = "Via"
	HeaderXForwardedFor                      = "X-Forwarded-For"
	HeaderXForwardedHost                     = "X-Forwarded-Host"
	HeaderXForwardedProto                    = "X-Forwarded-Proto"
	HeaderXForwardedProtocol                 = "X-Forwarded-Protocol"
	HeaderXForwardedSsl                      = "X-Forwarded-Ssl"
	HeaderXUrlScheme                         = "X-Url-Scheme"
	HeaderLocation                           = "Location"
	HeaderFrom                               = "From"
	HeaderHost                               = "Host"
	HeaderReferer                            = "Referer"
	HeaderReferrerPolicy                     = "Referrer-Policy"
	HeaderUserAgent                          = "User-Agent"
	HeaderAllow                              = "Allow"
	HeaderServer                             = "Server"
	HeaderAcceptRanges                       = "Accept-Ranges"
	HeaderContentRange                       = "Content-Range"
	HeaderIfRange                            = "If-Range"
	HeaderRange                              = "Range"
	HeaderContentSecurityPolicy              = "Content-Security-Policy"
	HeaderContentSecurityPolicyReportOnly    = "Content-Security-Policy-Report-Only"
	HeaderCrossOriginResourcePolicy          = "Cross-Origin-Resource-Policy"
	HeaderExpectCT                           = "Expect-CT"
	HeaderPermissionsPolicy                  = "Permissions-Policy"
	HeaderPublicKeyPins                      = "Public-Key-Pins"
	HeaderPublicKeyPinsReportOnly            = "Public-Key-Pins-Report-Only"
	HeaderStrictTransportSecurity            = "Strict-Transport-Security"
	HeaderUpgradeInsecureRequests            = "Upgrade-Insecure-Requests"
	HeaderXContentTypeOptions                = "X-Content-Type-Options"
	HeaderXDownloadOptions                   = "X-Download-Options"
	HeaderXFrameOptions                      = "X-Frame-Options"
	HeaderXPoweredBy                         = "X-Powered-By"
	HeaderXXSSProtection                     = "X-XSS-Protection"
	HeaderLastEventID                        = "Last-Event-ID"
	HeaderNEL                                = "NEL"
	HeaderPingFrom                           = "Ping-From"
	HeaderPingTo                             = "Ping-To"
	HeaderReportTo                           = "Report-To"
	HeaderTE                                 = "TE"
	HeaderTrailer                            = "Trailer"
	HeaderTransferEncoding                   = "Transfer-Encoding"
	HeaderSecWebSocketAccept                 = "Sec-WebSocket-Accept"
	HeaderSecWebSocketExtensions             = "Sec-WebSocket-Extensions"
	HeaderSecWebSocketKey                    = "Sec-WebSocket-Key"
	HeaderSecWebSocketProtocol               = "Sec-WebSocket-Protocol"
	HeaderSecWebSocketVersion                = "Sec-WebSocket-Version"
	HeaderAcceptPatch                        = "Accept-Patch"
	HeaderAcceptPushPolicy                   = "Accept-Push-Policy"
	HeaderAcceptSignature                    = "Accept-Signature"
	HeaderAltSvc                             = "Alt-Svc"
	HeaderDate                               = "Date"
	HeaderIndex                              = "Index"
	HeaderLargeAllocation                    = "Large-Allocation"
	HeaderLink                               = "Link"
	HeaderPushPolicy                         = "Push-Policy"
	HeaderRetryAfter                         = "Retry-After"
	HeaderServerTiming                       = "Server-Timing"
	HeaderSignature                          = "Signature"
	HeaderSignedHeaders                      = "Signed-Headers"
	HeaderSourceMap                          = "SourceMap"
	HeaderUpgrade                            = "Upgrade"
	HeaderXDNSPrefetchControl                = "X-DNS-Prefetch-Control"
	HeaderXPingback                          = "X-Pingback"
	HeaderXRequestID                         = "X-Request-ID"
	HeaderXRequestedWith                     = "X-Requested-With"
	HeaderXRobotsTag                         = "X-Robots-Tag"
	HeaderXUACompatible                      = "X-UA-Compatible"
	HeaderAccessControlAllowPrivateNetwork   = "Access-Control-Allow-Private-Network"
	HeaderAccessControlRequestPrivateNetwork = "Access-Control-Request-Private-Network"
)

HTTP Headers were copied from net/http.

View Source
const (
	CookieSameSiteDisabled   = "disabled" // not in RFC, just control "SameSite" attribute will not be set.
	CookieSameSiteLaxMode    = "lax"
	CookieSameSiteStrictMode = "strict"
	CookieSameSiteNoneMode   = "none"
)

Cookie SameSite https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7

View Source
const (
	ConstraintInt             = "int"
	ConstraintBool            = "bool"
	ConstraintFloat           = "float"
	ConstraintAlpha           = "alpha"
	ConstraintGUID            = "guid"
	ConstraintMinLen          = "minLen"
	ConstraintMaxLen          = "maxLen"
	ConstraintLen             = "len"
	ConstraintBetweenLen      = "betweenLen"
	ConstraintMinLenLower     = "minlen"
	ConstraintMaxLenLower     = "maxlen"
	ConstraintBetweenLenLower = "betweenlen"
	ConstraintMin             = "min"
	ConstraintMax             = "max"
	ConstraintRange           = "range"
	ConstraintDatetime        = "datetime"
	ConstraintRegex           = "regex"
)

Route Constraints

Variables

View Source
var (
	JSONEncoder = json.NewEncoder
	JSONDecoder = json.NewDecoder
	XMLEncoder  = xml.NewEncoder
	XMLDecoder  = xml.NewDecoder
)

JSON/XML Encoders and Decoders

Functions

This section is empty.

Types

type Bind

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

Bind struct

func NewBind

func NewBind(r *http.Request, enableSplitting ...bool) *Bind

NewBind creates a new Bind instance.

func (*Bind) Body

func (b *Bind) Body(out any) error

Body binds the request body into the struct, map[string]string and map[string][]string. It supports decoding the following content types based on the Content-Type header: application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data If none of the content types above are matched, it'll take a look custom binders by checking the MIMETypes() method of custom binder. If there're no custom binder for mşme type of body, it will return a ErrUnprocessableEntity error.

func (*Bind) Cookie

func (b *Bind) Cookie(out any) error

Cookie binds the request cookie strings into the struct, map[string]string and map[string][]string. NOTE: If your cookie is like key=val1,val2; they'll be binded as an slice if your map is map[string][]string. Else, it'll use last element of cookie.

func (*Bind) Form

func (b *Bind) Form(out any) error

Form binds the form into the struct, map[string]string and map[string][]string.

func (*Bind) Header

func (b *Bind) Header(out any) error

Header binds the request header strings into the struct, map[string]string and map[string][]string.

func (*Bind) JSON

func (b *Bind) JSON(out any) error

JSON binds the body string into the struct.

func (*Bind) MultipartForm

func (b *Bind) MultipartForm(out any, size ...int64) error

MultipartForm binds the multipart form into the struct, map[string]string and map[string][]string. Parameter size is the maximum memory in bytes used to parse the form, default is 32MB.

func (*Bind) Query

func (b *Bind) Query(out any) error

Query binds the query string into the struct, map[string]string and map[string][]string.

func (*Bind) Release added in v1.1.3

func (b *Bind) Release()

Release releases the Bind instance back into the pool.

func (*Bind) URI

func (b *Bind) URI(out any) error

URI binds the route parameters into the struct, map[string]string and map[string][]string.

func (*Bind) XML

func (b *Bind) XML(out any) error

XML binds the body string into the struct.

type M

type M map[string]any

M is a convenience alias for quickly building a map structure.

type Render

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

Render struct

func NewRender

func NewRender(w http.ResponseWriter, r ...*http.Request) *Render

NewRender creates a new NewRender instance.

func (*Render) ContentType added in v1.1.2

func (r *Render) ContentType(v string)

ContentType sets the Content-Type header for an HTTP response.

func (*Render) Cookie

func (r *Render) Cookie(cookie *http.Cookie)

Cookie sets a cookie in the response.

func (*Render) Data

func (r *Render) Data(v []byte)

Data writes raw bytes to the response, setting the Content-Type as application/octet-stream if not set.

func (*Render) Download

func (r *Render) Download(filepath, filename string)

Download sends a file to the response and prompting it to be downloaded by setting the Content-Disposition header.

func (*Render) EventStream

func (r *Render) EventStream(v any)

EventStream writes a stream of JSON objects from a channel to the response and setting the Content-Type as text/event-stream if not set.

func (*Render) File

func (r *Render) File(filepath string)

File sends a file to the response.

func (*Render) Flush

func (r *Render) Flush()

Flush sends any buffered data to the response.

func (*Render) HTML

func (r *Render) HTML(v string)

HTML writes a string to the response, setting the Content-Type as text/html if not set.

func (*Render) Header

func (r *Render) Header(key, value string)

Header sets the provided header key/value pair in the response.

func (*Render) Hijack added in v1.1.0

func (r *Render) Hijack() (http.Hijacker, bool)

Hijack returns the underlying Hijacker interface.

func (*Render) JSON

func (r *Render) JSON(v any)

JSON marshals 'v' to JSON, automatically escaping HTML and setting the Content-Type as application/json if not set.

func (*Render) JSONP

func (r *Render) JSONP(callback string, v any)

JSONP marshals 'v' to JSON, automatically escaping HTML and setting the Content-Type as application/javascript if not set.

func (*Render) NoContent

func (r *Render) NoContent()

NoContent returns a HTTP 204 "No Content" response.

func (*Render) PlainText

func (r *Render) PlainText(v string)

PlainText writes a string to the response, setting the Content-Type as text/plain if not set.

func (*Render) Redirect

func (r *Render) Redirect(url string)

Redirect replies to the request with a redirect to url, which may be a path relative to the request path.

func (*Render) RedirectPermanent added in v1.1.2

func (r *Render) RedirectPermanent(url string)

RedirectPermanent replies to the request with a redirect to url, which may be a path relative to the request path.

func (*Render) Release added in v1.1.3

func (r *Render) Release()

Release puts the Render instance back into the pool.

func (*Render) SSEvent added in v1.1.0

func (r *Render) SSEvent(event renderer.SSEvent)

SSEvent writes a Server-Sent Event to the response and setting the Content-Type as text/event-stream if not set.

func (*Render) SendStatus added in v1.2.0

func (r *Render) SendStatus(status int)

SendStatus is a warpper for WriteHeader method, will send the status code immediately.

func (*Render) Status

func (r *Render) Status(status int)

Status sets the HTTP status code for the response, but does not send it yet. This is because once the status is sent, no header can be modified.

func (*Render) Stream added in v1.1.0

func (r *Render) Stream(step func(w io.Writer) bool) bool

Stream sends a streaming response and returns a boolean indicates "Is client disconnected in middle of stream"

func (*Render) WithoutCookie

func (r *Render) WithoutCookie(name string)

WithoutCookie deletes a cookie in the response.

func (*Render) XML

func (r *Render) XML(v any)

XML marshals 'v' to XML, setting the Content-Type as application/xml if not set. It will automatically prepend a generic XML header (see encoding/xml.Header) if one is not found in the first 100 bytes of 'v'.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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