braza

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2025 License: BSD-3-Clause Imports: 34 Imported by: 0

README

braza

See the Documentation

Features

- File Watcher (hot reload)
- Error management
- Routers
- Schema Validator (with c3po package)
- Rendering built-in (template/html)
- Endpoints
- Implements net/http

- Supports
    - Jwt 
    - Cors 
    - Sessions
    - Websocket
    - Middleware & Next
    - URL Route builder

Simple Example

With a correctly configured Go toolchain:
go get 5tk.dev/braza

main.go

package main

import "5tk.dev/braza"

func main() {
 app := braza.NewApp()
 app.GET("/hello", helloWorld)
 app.GET("/hello/{name}", helloUser) // 'name' is any string
 app.GET("/hello/{userID:int}", userByID) // 'userID' is only int

 fmt.Println(app.Listen())
}

func helloWorld(ctx *braza.Ctx) {
 hello := map[string]any{"Hello": "World"}
 ctx.JSON(hello, 200)
}

func helloUser(ctx *braza.Ctx) {
 rq := ctx.Request   // current Request
 name := rq.PathArgs["name"]
 ctx.HTML("<h1>Hello "+name+"</h1>", 200)
}

func userByID(ctx *braza.Ctx) {
 rq := ctx.Request   // current Request
 id := rq.PathArgs["userID"]
 user := AnyQuery(id)
 ctx.JSON(user, 200)
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrHttpAbort        = errors.New("abort")
	ErrorNotFound       = errors.New("404 Not Found")
	ErrorMethodMismatch = errors.New("405 Method Not Allowed")
)

Functions

func Daemon

func Daemon(apps ...*App) error

func MountSchemaFromRequest

func MountSchemaFromRequest(f *c3po.Fielder, rq *Request) c3po.Schema

func SetCookie

func SetCookie(h http.Header, cookie *http.Cookie)

Set a Cookie. Has the same effect as 'Response.SetCookie'

func SetHeader

func SetHeader(w http.ResponseWriter, h http.Header)

Write the headers in the response

func TypeOf

func TypeOf(obj any) string

Alias of 'fmt.Sprintf("%T", obj)'

Types

type App

type App struct {
	// Main Router
	*Router

	// Main Config
	*Config

	/*
		custom auth parser
			app.BasicAuth = (ctx *braza.Ctx) {
				a := ctx.Request.Header.Get("Authorization")
				if a != ""{
					...
					return user,pass, true
				}
				return "","",false
			}
	*/
	BasicAuth func(*Ctx) (user string, pass string, ok bool) // custom func to parse Authorization Header
	/*
		exec after each request (if the application dont crash)
			app.AfterRequest = (ctx *braza.Ctx) {
				h := ctx.Response.Header()
				h.Set("X-Foo","Bar")
				ctx.Response.SetHeader(h)
				...
			}
	*/
	AfterRequest Func

	/*
		exec before each request
			app.BeforeRequest = (ctx *braza.Ctx) {
				db := database.Open()
				ctx.Global["db"] = db
				user,pass,ok := ctx.Request.BasicAuth()
				if ok {
					ctx.Global["user"] = user
				}
			}
	*/
	BeforeRequest Func

	/*
		exec after close each conn ( this dont has effect in response)
			app.TearDownRequest = (ctx *braza.Ctx) {
				database.Close()
				log.Print(...)
				...
			}
	*/
	TearDownRequest Func

	// The Http.Server
	Srv *http.Server
	// contains filtered or unexported fields
}

func NewApp

func NewApp(cfg *Config) *App

Create a new app with a default settings

app := NewApp(nil) // or NewApp(*braza.Config{})
...
app.Listen()

func (*App) Build

func (app *App) Build(addr ...string)

Build the App, but not start serve

example:

func index(ctx braza.Ctx){}

// it's work
func main() {
	app := braza.NewApp()
	app.GET("/",index)
	app.Build()
	app.UrlFor("index",true)
}
// it's don't work
func main() {
	app := braza.NewApp()
	app.GET("/",index)
	app.UrlFor("index",true)
}

func (*App) ErrorHandler

func (app *App) ErrorHandler(statusCode int, f Func)

Custom Http Error Handler

app.ErrorHandler(401,(ctx *braza.Ctx) {
	ctx.HTML("Access denied",401)
})
app.ErrorHandler(404,(ctx *braza.Ctx) {
	ctx.HTML("Hey boy, you're a little lost",404)
})

func (*App) Listen

func (app *App) Listen(host ...string) (err error)

Start Listener in http

func (*App) ListenTLS

func (app *App) ListenTLS(certFile, certKey string, host ...string) (err error)

Start Listener in https

func (*App) Mount

func (app *App) Mount(routers ...*Router)

Register Router in app

func main() {
	api := braza.NewRouter("api")
	api.post("/products")
	api.get("/products/{productID:int}")

	app := braza.NewApp(nil)
	app.Mount(api)
	// do anything ...
	app.Listen()
}

func (*App) ServeHTTP

func (app *App) ServeHTTP(wr http.ResponseWriter, req *http.Request)

http.Handler

func (*App) ShowRoutes

func (app *App) ShowRoutes()

func (*App) UrlFor

func (app *App) UrlFor(name string, external bool, args ...string) string

Url Builder

app.GET("/users/{userID:int}", index)

app.UrlFor("index", false, "userID", "1"}) //  /users/1
app.UrlFor("index", true, "userID", "1"}) // http://servername/users/1

type Config

type Config struct {
	Env                     string           // environmnt (default 'development')
	SecretKey               string           // for sign session (default ”)
	Servername              string           // for build url routes and route match (default ”)
	ListeningInTLS          bool             // UrlFor return a URl with schema in "https:" (default 'false')
	TemplateFolder          string           // for render Templates Html. Default "templates/"
	TemplateFuncs           template.FuncMap `validate:"-"`
	DisableParseFormBody    bool             // Disable default parse of Request.Form -> if true, use Request.ParseForm()
	DisableTemplateReloader bool             // if app in dev mode, disable template's reload (default false)
	StaticFolder            string           // for serve static files (default '/assets')
	StaticUrlPath           string           // url uf request static file (default '/assets')
	DisableStatic           bool             // disable static endpoint for serving static files (default false)
	Silent                  bool             // don't print logs (default false)
	DisableWarnOn405        bool
	LogFile                 string // save log info in file (default ”)
	DisableFileWatcher      bool   // disable autoreload in dev mode (default false)

	SessionExpires          time.Duration `validate:"-"` // (default 30 minutes)
	SessionPermanentExpires time.Duration `validate:"-"` // (default 31 days)

	SessionPublicKey  *rsa.PublicKey  `validate:"-"`
	SessionPrivateKey *rsa.PrivateKey `validate:"-"`
	// contains filtered or unexported fields
}

func NewConfig

func NewConfig() *Config

Usage:

env := "dev"
devConfig := braza.NewConfig()
prodConfig := braza.NewConfig()
var cfg  *Config

if env == "dev"{
	cfg = devConfig
} else {
	cfg = prodConfig
}
app := braza.NewApp(cfg)
...

func NewConfigFromFile

func NewConfigFromFile(file string) *Config

func (*Config) SetupFromFile

func (c *Config) SetupFromFile(filename string) error

setup config from json, yalm

type Cors

type Cors struct {
	MaxAge string // Access-Control-Max-Age
	// ex:
	//  []string{"example.com","www.example.com"}
	AllowOrigins []string // Access-Control-Allow-Origin
	// ex:
	// 	[]string{"*","GET","POST"}
	AllowMethods []string // Access-Control-Allow-Methods
	// ex:
	// []string{"Authorization","*"}
	AllowHeaders []string // Access-Control-Allow-Headers
	// ex:
	// []string{"X-Header"}
	ExposeHeaders    []string // Access-Control-Expose-Headers
	RequestMethod    string   // Access-Control-Request-Method
	AllowCredentials bool     // Access-Control-Allow-Credentials
	// contains filtered or unexported fields
}

If present on route or router, allows resource sharing between origins

type Ctx

type Ctx struct {
	// Clone Current App
	App *App

	/*
		global variables of current request
			app.BeforeRequest = (ctx *braza.Ctx){
				db := database.Open().Session()
				ctx.Global["db"] = db
				user := db.FindUser()
				ctx.Global["user"] = user

			}
			func index(ctx *braza.Ctx){
				db := ctx.Global["db"].(database.DB)
				user := ctx.Global["user"].(*User)
				...
			}
	*/
	Global map[string]any

	/*
		Current Cookie Session
		func login(ctx *braza.Ctx){
				db := ctx.Global["db"].(database.DB)
				username,pass,ok := ctx.Request.BasicAuth()
				if ok{
					user := &User{}
					db.Where("username = ?",username).Find(user)
					if user.CompareHashPass(pass){
						ctx.Session.Set("user",user.id)
					}
				}
				ctx.Unauthorized()
			}
	*/
	Session *Session

	/*
		Current Response
			func foo(ctx *braza.Ctx) {
				ctx.JSON(map[string]any{
					"foo":"bar",
				}, 200)
			}
			func foo(ctx *braza.Ctx) {
				ctx.HTML("<h1>Hello</h1>",200)
			}
			func foo(ctx *braza.Ctx) {
				ctx.RenderTemplate("index.html")
		  	}
	*/
	*Response

	/*
		Current Request
	*/
	Request *Request

	/*
		New Schema valid from route schema
			Route{
				Url:"/{foo}/{bar:int}"
				Func: foo,
				Schema: &Schema{}
			}

			type Schema struct {
				Bar int `braza:"in=args"`
				Foo string `braza:"in=args"`
				File *braza.File `braza:"in=files"`
				Files []*braza.File `braza:"in=files"`
				XHeader string `braza:"in=headers"`
				User string `braza:"in=auth,name=username"`
				Pass string `braza:"in=auth,name=password"`
				Limit int `braza:"in=query"` // /path/search?limit=1&offset=2
				Offset int `braza:"in=query"` // /path/search?limit=1&offset=2

				Text string `braza:"in=body"`
				Text2 string  // deafult is 'in=body'.
			}

			func foo(ctx *braza.Ctx) {
				sch := ctx.Schema.(*Schema)
				...
			}
	*/
	Schema        Schema
	SchemaFielder *c3po.Fielder

	/*
		Contains information about the current request, route, etc...

		Can only be accessed if there is a match. otherwise the values ​​will be null
			func xpto(ctx *braza.Ctx) {
				route := ctx.Matchinfo.Route
				router := ctx.Matchinfo.Router
				...
			}
	*/
	MatchInfo *MatchInfo
	// contains filtered or unexported fields
}

func CtxForTests

func CtxForTests(app *App, rq *http.Request) *Ctx

func NewCtx

func NewCtx(app *App, wr http.ResponseWriter, rq *http.Request) *Ctx

Returns a new *braza.Ctx

func (*Ctx) Next

func (ctx *Ctx) Next()

executes the next middleware or main function of the request

func (*Ctx) UrlFor

func (ctx *Ctx) UrlFor(name string, external bool, args ...string) string

type File

type File struct {
	Filename     string
	ContentType  string
	ContentLeght int
	Stream       *bytes.Buffer
}

func NewFile

func NewFile(p *multipart.Part) *File

type Func

type Func func(ctx *Ctx)

func Handler

func Handler(h http.Handler) Func

func (Func) String

func (f Func) String() string

type Jsonify

type Jsonify interface {
	ToJson() any
}

type ManyJsonify

type ManyJsonify[C Jsonify] []C

func (ManyJsonify[C]) ToJson

func (mj ManyJsonify[C]) ToJson() any

type ManyMapper

type ManyMapper[C Mapper] []Mapper

func (ManyMapper[C]) ToMap

func (mm ManyMapper[C]) ToMap() []map[string]any

type MapCtrl

type MapCtrl map[string]*Meth

type Mapper

type Mapper interface {
	ToMap() map[string]any
}

type MatchInfo

type MatchInfo struct {
	Func
	Match            bool
	Route            *Route
	Router           *Router
	MethodNotAllowed error
	// contains filtered or unexported fields
}

type Meth

type Meth struct {
	Func          Func
	Schema        Schema
	RespSchema    RespSchema
	SchemaFielder *c3po.Fielder
}

type Request

type Request struct {
	Header http.Header

	Body *bytes.Buffer
	Method,
	RemoteAddr,
	RequestURI,
	ContentType string

	ContentLength int

	URL      *url.URL
	Host     string
	Port     string
	Form     map[string]any
	PathArgs map[string]string
	Mime     map[string]string
	Query    url.Values
	Files    map[string][]*File
	Cookies  map[string]*http.Cookie

	TransferEncoding []string

	Proto      string // "HTTP/1.0"
	ProtoMajor int    // 1
	ProtoMinor int    // 0
	// contains filtered or unexported fields
}

func NewRequest

func NewRequest(req *http.Request, ctx *Ctx) *Request

func (*Request) BasicAuth

func (r *Request) BasicAuth() (username, password string, ok bool)

func (*Request) Clone

func (r *Request) Clone(ctx context.Context) *Request

func (*Request) Context

func (r *Request) Context() context.Context

func (*Request) Ctx

func (r *Request) Ctx() *Ctx

func (*Request) HttpRequest

func (r *Request) HttpRequest() *http.Request

func (*Request) ParseForm

func (r *Request) ParseForm()

func (*Request) ProtoAtLeast

func (r *Request) ProtoAtLeast(major, minor int) bool

func (*Request) Referer

func (r *Request) Referer() string

func (*Request) RequestURL

func (r *Request) RequestURL() string

Returns the current url

func (*Request) UrlFor

func (r *Request) UrlFor(name string, external bool, args ...string) string

URL Builder

app.GET("/", index)
app.GET("/login", login)

app.UrlFor("login", false, "next", "currentUrl"})
// results: /login?next=currentUrl

app.UrlFor("login", true, "token", "foobar"})
// results: http://yourAddress/login?token=foobar

// example
func index(ctx *braza.Ctx) {
	req := ctx.Request
	rsp := ctx.Response
	userID, ok := ctx.Global["user"]
	if !ok {
		next := r.RequestUrl()
		rsp.Redirect(req.UrlFor("login", true, "next", next))
		//  redirect to: http://youraddress/login?next=http://yourhost:port/
	}
	... you code here
}

func (*Request) UserAgent

func (r *Request) UserAgent() string

func (*Request) Websocket

func (r *Request) Websocket() (*websocket.Conn, error)

func (*Request) WithContext

func (r *Request) WithContext(ctx context.Context) *Request

type RespSchema

type RespSchema map[int]any

type Response

type Response struct {
	*bytes.Buffer

	StatusCode int
	// contains filtered or unexported fields
}

func NewResponse

func NewResponse(wr http.ResponseWriter, ctx *Ctx) *Response

func NewResponseForTest

func NewResponseForTest(ctx *Ctx) *Response

func (*Response) Abort

func (r *Response) Abort(code int)

func (*Response) BadRequest

func (r *Response) BadRequest()

func (*Response) CheckErr

func (r *Response) CheckErr(err error)

if err != nil, return a 500 Intenal Server Error

func (*Response) Close

func (r *Response) Close()

func (*Response) Created

func (r *Response) Created()

func (*Response) Forbidden

func (r *Response) Forbidden()

func (*Response) HTML

func (r *Response) HTML(body any, code int)

func (Response) Header

func (r Response) Header() http.Header

func (*Response) Hijack

func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error)

func (*Response) ImATaerpot

func (r *Response) ImATaerpot()

func (*Response) InternalServerError

func (r *Response) InternalServerError()

func (*Response) JSON

func (r *Response) JSON(body any, code int)

func (*Response) MethodNotAllowed

func (r *Response) MethodNotAllowed()

func (*Response) NoContent

func (r *Response) NoContent()

func (*Response) NotFound

func (r *Response) NotFound()

func (*Response) Ok

func (r *Response) Ok()

func (*Response) Redirect

func (r *Response) Redirect(url string)

Redirect to Following URL

func (*Response) RenderTemplate

func (r *Response) RenderTemplate(tmpl string, data ...any)

func (*Response) ServeFile

func (r *Response) ServeFile(pathToFile string)

Serve File

func (*Response) SetCookie

func (r *Response) SetCookie(cookie *http.Cookie)

func (Response) SetHeader

func (r Response) SetHeader(h http.Header)

func (*Response) TEXT

func (r *Response) TEXT(body any, code int)

func (*Response) Unauthorized

func (r *Response) Unauthorized()

func (Response) Write

func (r Response) Write(b []byte) (int, error)

func (Response) WriteHeader

func (r Response) WriteHeader(statusCode int)

type Route

type Route struct {
	/*
		# url patterns
			"" is same "/"
			"/batata"	// match literal "/batata"
			"/{name}"	// match any string (ex: batata1234)
			"/{id:int}"	// match on numbers (ex: 12345)
			"/{path:*}"	|| "/{path:path}" // match anything
			"/{var1:int}/{var2}/{var3}" // is allowed
			`/(\d+)` // regex work too
	*/
	Url string

	// # Route Name
	//	ctx.UrlFor("route Name"...
	Name string

	Func Func

	/*
		allow Cors on this route
		&Cors{
			AllowOrigins: []string{"example.com","www.example.com"},
			AllowMethods: []string{"*","GET","POST"},
			AllowHeaders: []string{"Authorization","*"},
			ExposeHeaders: []string{"X-Header"},
			AllowCredentials: true
		}
	*/
	Cors *Cors

	Schema     Schema
	RespSchema RespSchema

	/*
		# a peculiar way of establishing routes
			Route{
				Name:"foo",
				Url:"/foo",
				MapCtrl: braza.MapCtrl{
					"GET": &braza.Meth{
						Func: Foo,
						Schema: &SchemaFoo{}
					},
					"POST": &braza.Meth{
						Func: Bar,
						Schema: &SchemaBar{}
					},
					"DELETE": &braza.Meth{
						Func: Xpto,
						Schema: &SchemaXpto{}
					},
				},
			}
	*/
	MapCtrl MapCtrl

	// HTTP methods allowed on this route
	//		[]string{"GET","POST","PATCH",...
	Methods []string

	// Func wiil exec before this route
	//		[]Func{	GetUser, HasAUth,...
	Middlewares []Func
	// contains filtered or unexported fields
}

func CONNECT

func CONNECT(url string, f Func) *Route

func DELETE

func DELETE(url string, f Func) *Route

func GET

func GET(url string, f Func) *Route
func HEAD(url string, f Func) *Route

func OPTIONS

func OPTIONS(url string, f Func) *Route

func PATCH

func PATCH(url string, f Func) *Route

func POST

func POST(url string, f Func) *Route

func PUT

func PUT(url string, f Func) *Route

func TRACE

func TRACE(url string, f Func) *Route

func (*Route) GetRouter

func (r *Route) GetRouter() *Router

type Router

type Router struct {
	Cors        *Cors
	Name        string
	Routes      []*Route
	Prefix      string
	Subdomain   string // only {sub} or {sub:int}
	WsUpgrader  *websocket.Upgrader
	Middlewares []Func
	StrictSlash bool
	// contains filtered or unexported fields
}

func NewRouter

func NewRouter(name string) *Router

func (*Router) Add

func (r *Router) Add(url, name string, f Func, meths []string)

func (*Router) AddRoute

func (r *Router) AddRoute(routes ...*Route)

func (*Router) CONNECT

func (r *Router) CONNECT(url string, f Func)

func (*Router) DELETE

func (r *Router) DELETE(url string, f Func)

func (*Router) GET

func (r *Router) GET(url string, f Func)

func (*Router) HEAD

func (r *Router) HEAD(url string, f Func)

func (*Router) OPTIONS

func (r *Router) OPTIONS(url string, f Func)

func (*Router) PATCH

func (r *Router) PATCH(url string, f Func)

func (*Router) POST

func (r *Router) POST(url string, f Func)

func (*Router) PUT

func (r *Router) PUT(url string, f Func)

func (*Router) TRACE

func (r *Router) TRACE(url string, f Func)

type Schema

type Schema any

example:

type Schema struct {
	Bar int `braza:"in=args"`
	File *braza.File `braza:"in=files"`
	Files []*braza.File `braza:"in=files"`
	XHeader string `braza:"in=headers"`
	User string `braza:"in=auth,name=username"`
	Pass string `braza:"in=auth,name=password"`
	Limit int `braza:"in=query"` // /path/search?limit=1&offset=2
	Offset int `braza:"in=query"` // /path/search?limit=1&offset=2

	Text string `braza:"in=body"`
	Text2 string  // deafult is 'in=body'.
}

Route{
	Name:"foo",
	Url:"/{bar:int}",
	Schema: &Schema{},
}

func AnyHandler(ctx *braza.Ctx){
	u := ctx.Schema.(*Schema)
	...
}

type Session

type Session struct {
	Permanent bool
	// contains filtered or unexported fields
}

func (*Session) Del

func (s *Session) Del(key string) string

Delete a Value from Session

func (*Session) Get

func (s *Session) Get(key string) string

Returns a session value based on the key. If key does not exist, returns an empty string

func (*Session) GetSign

func (s *Session) GetSign(ctx *Ctx) (string, error)

Returns a JWT Token from session data

func (*Session) Set

func (s *Session) Set(key, value string)

This inserts a value into the session

Directories

Path Synopsis
examples
api command
reverseProxy command

Jump to

Keyboard shortcuts

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