phx

package module
v0.3.11 Latest Latest
Warning

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

Go to latest
Published: Feb 25, 2024 License: MIT Imports: 20 Imported by: 0

README ΒΆ

🐦 Phx

A little, highly opinated framework to create complete web apps.

Demo:

package main

import (
	"littlecash/locale"
	"littlecash/static"
	"littlecash/views"
	"log"
	"net/http"
	"time"

	"github.com/deltegui/phx"
	"github.com/deltegui/phx/core"
	"github.com/deltegui/phx/cypher"
	"github.com/deltegui/phx/session"
)

func ParseAll(r *phx.Router) {
	r.Parse(views.DemoIndex, "index.html", "demo/index.html")
	r.Parse(views.Login, "layout.html", "account/layout.html", "account/login.html")
	r.Parse(views.Arr, "arr.html", "demo/arr.html")
	r.ShowAvailableTemplates()
}

func main() {
	r := phx.NewRouter()
	r.Bootstrap()
	r.Add(func() core.Cypher {
		csrfpass := "you can generate a password with the framework or let it be random"
		return cypher.NewWithPasswordAsString(csrfpass)
	})
	r.ShowAvailableBuilders()

	r.Use(phx.HttpLogMiddleware)

	r.UseStaticEmbedded(static.Files)
	r.UseTemplate(views.Files)
	r.AddDefaultTemplateFunctions()
	r.UseCsrf(15 * time.Minute)
	r.UseLocalization(locale.Files, locale.Shared, locale.Errors)
	r.UseSessionInMemory(1 * time.Hour)
	r.UseSessionAuthWithRedirection("/login")

	views.ParseAll(r)

	r.Get("/", func() phx.Handler {
		return func(ctx *phx.Context) {
			ctx.StringOK("Hola mundo desde aqui")
		}
	})
	r.Get("/demo", func() phx.Handler {
		return func(ctx *phx.Context) {
			ctx.Render(http.StatusOK, views.DemoIndex, struct{}{})
		}
	}, r.Authorize())
	r.Get("/change/:lang", func() phx.Handler {
		return func(ctx *phx.Context) {
			from := ctx.GetCurrentLanguage()
			to := ctx.GetUrlParam("lang")
			if len(to) == 0 {
				ctx.String(http.StatusBadRequest, "Nothing to change!")
				return
			}
			ctx.ChangeLanguage(to)
			ctx.StringOK("Changed from '%s' to '%s'", from, to)
		}
	})
	r.Post("/demo", func(hasher core.Hasher) phx.Handler {
		type f struct {
			Name     string `validate:"required,min=3,max=255"`
			Password string `validate:"required,min=3,max=255"`
		}
		return func(ctx *phx.Context) {
			var form f
			ctx.ParseForm(&form)
			errs := ctx.Validate(form)
			if errs != nil {
				ctx.RenderWithErrors(http.StatusBadRequest, views.DemoIndex, struct{}{}, errs)
				return
			}
			form.Password = hasher.Hash(form.Password)
			ctx.JsonOK(form)
		}
	}, r.Authorize())
	r.Get("/login", func() phx.Handler {
		return func(ctx *phx.Context) {
			ctx.RenderOK(views.Login, AccountViewModel{})
		}
	})
	r.Post("/login", func() phx.Handler {
		return func(ctx *phx.Context) {
			var vm AccountViewModel
			ctx.ParseForm(&vm)
			if errs := ctx.Validate(vm); errs != nil {
				log.Println("MAL")
				ctx.RenderWithErrors(http.StatusBadRequest, views.Login, vm, errs)
				return
			}
			ctx.CreateSessionCookie(session.User{
				Id:   0,
				Name: vm.Name,
				Role: core.RoleAdmin,
			})
			ctx.Redirect("/demo")
		}
	})
	r.Get("/logout", func() phx.Handler {
		return func(ctx *phx.Context) {
			ctx.DestroySession()
			ctx.Redirect("/login")
		}
	})

	r.Get("/arr", func() phx.Handler {
		return func(ctx *phx.Context) {
			ctx.RenderOK(views.Arr, nil)
		}
	})

	r.Post("/arr", func() phx.Handler {
		return func(ctx *phx.Context) {
			var names []string
			if err := ctx.ParseJson(&names); err != nil {
				ctx.String(http.StatusBadRequest, "Invalid JSON")
				return
			}
			log.Println("OK")
			ctx.JsonOK(names)
		}
	})

	phx.PrintLogoEmbedded(views.Files, "banner.txt")
	r.Run(":3000")
}

type AccountViewModel struct {
	Name           string `validate:"required,min=3,max=255"`
	ErrorMessage   string
	HaveBeenLogout bool
}

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

func PrintLogo(logoFile string)

PrintLogo takes a file path and prints your fancy ascii logo. It will fail if your file is not found.

func PrintLogoEmbedded ΒΆ added in v0.0.42

func PrintLogoEmbedded(fs embed.FS, path string)

PrintLogo takes a embedded filesystem and file path and prints your fancy ascii logo. It will fail if your file is not found.

func Redirect ΒΆ

func Redirect(to string) func() Handler

Types ΒΆ

type Builder ΒΆ

type Builder interface{}

Builder is a function that expects anything and retuns the type that builds. The type cant be func() interface{} cause some errors appears in runtime. So it's represented as an interface.

type Context ΒΆ added in v0.0.15

type Context struct {
	Req *http.Request
	Res http.ResponseWriter
	// contains filtered or unexported fields
}

func (*Context) BadRequest ΒΆ added in v0.2.4

func (ctx *Context) BadRequest(data string, a ...any) error

func (*Context) ChangeLanguage ΒΆ added in v0.0.25

func (ctx *Context) ChangeLanguage(to string)

func (*Context) CreateCookie ΒΆ added in v0.3.8

func (ctx *Context) CreateCookie(name, data string) error

func (*Context) CreateCookieOptions ΒΆ added in v0.3.8

func (ctx *Context) CreateCookieOptions(opt CookieOptions) error

func (*Context) DeleteCookie ΒΆ added in v0.3.8

func (ctx *Context) DeleteCookie(name string) error

func (*Context) Forbidden ΒΆ added in v0.3.4

func (ctx *Context) Forbidden(data string, a ...any) error

func (*Context) Get ΒΆ added in v0.3.0

func (r *Context) Get(key any) any

func (*Context) GetCurrentLanguage ΒΆ added in v0.0.18

func (ctx *Context) GetCurrentLanguage() string

func (*Context) GetLocalizer ΒΆ added in v0.1.2

func (ctx *Context) GetLocalizer(file string) localizer.Localizer

func (*Context) GetQueryParam ΒΆ added in v0.0.45

func (ctx *Context) GetQueryParam(name string) string

func (*Context) GetUrlParam ΒΆ added in v0.0.45

func (ctx *Context) GetUrlParam(name string) string

func (*Context) GetUser ΒΆ added in v0.0.15

func (ctx *Context) GetUser() session.User

func (*Context) HaveLocalizer ΒΆ added in v0.3.3

func (ctx *Context) HaveLocalizer() bool

func (*Context) HaveSession ΒΆ added in v0.1.1

func (ctx *Context) HaveSession() bool

func (*Context) InternalServerError ΒΆ added in v0.2.4

func (ctx *Context) InternalServerError(data string, a ...any) error

func (*Context) Json ΒΆ added in v0.0.15

func (ctx *Context) Json(status int, data any) error

func (*Context) JsonOK ΒΆ added in v0.0.38

func (ctx *Context) JsonOK(data interface{}) error

func (*Context) Localize ΒΆ added in v0.1.1

func (ctx *Context) Localize(file, key string) string

func (*Context) LocalizeError ΒΆ added in v0.1.1

func (ctx *Context) LocalizeError(err core.UseCaseError) string

func (*Context) LocalizeWithoutShared ΒΆ added in v0.1.1

func (ctx *Context) LocalizeWithoutShared(file, key string) string

func (*Context) NotContent ΒΆ added in v0.3.4

func (ctx *Context) NotContent() error

func (*Context) NotFound ΒΆ added in v0.2.4

func (ctx *Context) NotFound(data string, a ...any) error

func (*Context) OK ΒΆ added in v0.2.4

func (ctx *Context) OK(data string, a ...any) error

func (*Context) PaginationToVM ΒΆ added in v0.1.2

func (ctx *Context) PaginationToVM(pag pagination.Pagination) pagination.ViewModel

func (*Context) ParseForm ΒΆ added in v0.0.18

func (ctx *Context) ParseForm(dst interface{})

ParseForm parses req.Form and then serializes the form data to the dst struct using reflection. The form names should match to the 'html' tag or, if its not setted, to the field name. ParseForm only supports serializing data to one-depth structs. Example, using this struct as target:

type MyStruct struct {
		A bool,
		B int `html:"pagination.currentPage"`
}

And having this serialized form:

"A=false&pagination.currentPage=2"

Calling ParseForm like this (NOTE THAT A POINTER TO THE STRUCT IS BEING PASSED):

var s MyStruct phx.ParseForm(req, &s)

It will result to this fullfilled struct:

{ A = false, B: 2 }

The supported field types are:

  • int, int8, int16, int32, int64

  • uint, uint8, uint16, uint32, uint64

  • float32, float64

  • bool

  • string

  • time.Time

func (*Context) ParseJson ΒΆ added in v0.0.26

func (ctx *Context) ParseJson(dst any) error

func (*Context) ReadCookie ΒΆ added in v0.3.8

func (ctx *Context) ReadCookie(name string) (string, error)

func (*Context) Redirect ΒΆ added in v0.0.15

func (ctx *Context) Redirect(to string) error

func (*Context) RedirectCode ΒΆ added in v0.0.18

func (ctx *Context) RedirectCode(to string, code int) error

func (*Context) Render ΒΆ added in v0.0.15

func (ctx *Context) Render(status int, parsed string, vm interface{}) error

func (*Context) RenderOK ΒΆ added in v0.0.38

func (ctx *Context) RenderOK(parsed string, vm interface{}) error

func (*Context) RenderWithErrors ΒΆ added in v0.0.15

func (ctx *Context) RenderWithErrors(status int, parsed string, vm interface{}, formErrors map[string]string) error

func (*Context) Set ΒΆ added in v0.3.0

func (r *Context) Set(key, value any)

func (*Context) String ΒΆ added in v0.0.18

func (ctx *Context) String(status int, data string, a ...any) error

func (*Context) Validate ΒΆ added in v0.0.25

func (ctx *Context) Validate(s any) map[string]string

type CookieOptions ΒΆ added in v0.3.8

type CookieOptions struct {
	Name    string
	Expires time.Duration
	Value   string

	// Set if front scripts can access to cookie.
	// If its true, front script cannot access.
	// By default true.
	HttpOnly bool

	// Sets if cookies are only send through https.
	// If its true means https only. By default false.
	Secure bool
}

type Handler ΒΆ added in v0.0.15

type Handler func(c *Context) error

type Injector ΒΆ

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

Injector is an automated dependency injector inspired in Sping's DI. It will detect which builder to call using its return type. If the builder haver params, it will fullfill that params calling other builders that provides its types.

func NewInjector ΒΆ

func NewInjector() *Injector

NewInjector with default values

func (Injector) Add ΒΆ

func (injector Injector) Add(builder Builder)

Add a builder to the dependency injector.

func (Injector) CallBuilder ΒΆ

func (injector Injector) CallBuilder(builder Builder) interface{}

CallBuilder injecting all parameters with provided builders. If some parameter type cannot be found, it will panic

func (Injector) Get ΒΆ

func (injector Injector) Get(name interface{}) (interface{}, error)

Get returns a builded dependency

func (Injector) GetByType ΒΆ

func (injector Injector) GetByType(name reflect.Type) (interface{}, error)

GetByType returns a builded dependency identified by type

func (Injector) PopulateStruct ΒΆ

func (injector Injector) PopulateStruct(userStruct interface{})

PopulateStruct fills a struct with the implementations that the injector can create. Make sure you pass a reference and not a value

func (Injector) ResolveHandler ΒΆ

func (injector Injector) ResolveHandler(builder Builder) Handler

ResolveHandler created by a builder

func (Injector) Run ΒΆ added in v0.3.0

func (injector Injector) Run(runner Runner)

Run is a function that runs a Runner. Show Runner type for more information

func (Injector) ShowAvailableBuilders ΒΆ

func (injector Injector) ShowAvailableBuilders()

ShowAvailableBuilders prints all registered builders.

type Middleware ΒΆ

type Middleware func(Handler) Handler

type Renderer ΒΆ added in v0.3.0

type Renderer interface {
	Render(ctx *Context, status int, parsed string, vm interface{}) error
	RenderWithErrors(ctx *Context, status int, parsed string, vm interface{}, formErrors map[string]string) error
}

type Router ΒΆ added in v0.0.15

type Router struct {
	ErrorHandler func(*Context, error)
	// contains filtered or unexported fields
}

func NewRouter ΒΆ added in v0.0.15

func NewRouter() *Router

func NewRouterFromOther ΒΆ added in v0.0.15

func NewRouterFromOther(r *Router) *Router

func (*Router) Add ΒΆ added in v0.0.15

func (r *Router) Add(builder Builder)

func (*Router) Delete ΒΆ added in v0.0.15

func (r *Router) Delete(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Get ΒΆ added in v0.0.15

func (r *Router) Get(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Handle ΒΆ added in v0.0.15

func (r *Router) Handle(method, pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Head ΒΆ added in v0.0.15

func (r *Router) Head(pattern string, builder Builder, middlewares ...Middleware)

func (Router) Listen ΒΆ added in v0.3.0

func (r Router) Listen(address string)

func (*Router) Options ΒΆ added in v0.0.15

func (r *Router) Options(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Patch ΒΆ added in v0.0.15

func (r *Router) Patch(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) PopulateStruct ΒΆ added in v0.0.15

func (r *Router) PopulateStruct(s interface{})

func (*Router) Post ΒΆ added in v0.0.15

func (r *Router) Post(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Put ΒΆ added in v0.0.15

func (r *Router) Put(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Run ΒΆ added in v0.0.15

func (r *Router) Run(runner Runner)

func (*Router) ShowAvailableBuilders ΒΆ added in v0.0.15

func (r *Router) ShowAvailableBuilders()

func (*Router) Static ΒΆ added in v0.3.0

func (r *Router) Static(path string)

func (*Router) StaticEmbedded ΒΆ added in v0.3.0

func (r *Router) StaticEmbedded(fs embed.FS)

func (*Router) StaticMount ΒΆ added in v0.3.0

func (r *Router) StaticMount(url, path string)

func (*Router) StaticMountEmbedded ΒΆ added in v0.3.0

func (r *Router) StaticMountEmbedded(url string, fs embed.FS)

func (*Router) Trace ΒΆ added in v0.0.15

func (r *Router) Trace(pattern string, builder Builder, middlewares ...Middleware)

func (*Router) Use ΒΆ added in v0.0.15

func (r *Router) Use(middleware Middleware)

func (*Router) UseLocalization ΒΆ added in v0.0.19

func (r *Router) UseLocalization(files embed.FS, sharedKey, errorsKey string)

type Runner ΒΆ added in v0.3.0

type Runner interface{}

Runner is any funtion that returns void. It is use as an easy way to ask to the injetor to provide dependencies to do something. For example, imagine that we have an interface called UserDao and we just want do something with it outside any builder or dependecy created using this injector. The UserDao is registered this way:

injector.Add(db.NewUserDao)

Then, you can ask for the dependency to the injector this way:

var userDao db.UserDao
userDao = injector.GetByType(reflect.TypeOf(&userDao).Elem()).(db.UserDao)

Its pretty cumbersome huh? You have to do that because you know it is an interface. Using Runner you can just do this:

injector.Run(func(userDao db.UserDao) {
	[... do whatever you want with userdDao ...]
})

The callback function will be exectued inmediatly.

Jump to

Keyboard shortcuts

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