gomvc

package module
v1.0.96 Latest Latest
Warning

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

Go to latest
Published: Jan 21, 2023 License: Apache-2.0 Imports: 23 Imported by: 2

README

MySQL - MVC (Model View Controller) with Golang

MVC (Model View Controller) implementation with Golang using MySql database

Overview

This is a Golang package easy to use and build almost any MVC Web App connected to MySql database with just a few steps.
gomvc package requires a MySql Server up and running and a database ready to drive your web application.

Build a standard MVC (Model, View, Controller) style web app with minimum Golang code, like you use a classic MVC Framework.
Many features, many ready to use functions, highly customizable, embeded log and error handling


MVC
(databse CRUD)      (http req/resp) 
     Model <--------> Controller
         \            /    
          \          /
           \        /
            \      /
             \    /
              View
      (text/template files)
Basic Steps
  • Edit the config file
  • Load config file config.yaml
  • Connect to MySql database
  • Write code to initialize your Models and Controllers
  • Write your standard text/Template files (Views)
  • Start your server and enjoy
This package includes :

MySql Driver : github.com/go-sql-driver/mysql
http Router : github.com/go-chi/chi/v5
csrf middleware :github.com/justinas/nosurf
Session middleware : github.com/alexedwards/scs/v2

Features

  • Easy to learn, use and build.
  • Flexibility and Customization
  • Embeded Authentication using database table if needed.
  • Embeded libraries like : session managment, csrf middleware, http router
  • Embeded info log and server error handling
  • Strong MVC pattern
  • Models with many features and easy to use functions
  • Models with build in relational functionlity with other database tables
  • Controlles with simple yet powerful http handling
  • Ability to attach our own functions to Controller and requests for more customized http handling
  • Working Examples to cover almost every case.

Installation

This package requires Go 1.12 or newer.

$ go get github.com/kostasdak/gomvc

Note: If you're using the traditional GOPATH mechanism to manage dependencies, instead of modules, you'll need to go get and import github.com/kostasdak/gomvc



Template file names general rules

It is recomended to use the folowing rule for template filenames. All template files must have .tmpl extension

  • Template layout
    This file is the layout of your app base.layout.html

  • Pages
    If a page needs a data from a databese table use this pattern : [dbtable].[action].tmpl
    If a page is a static page you can use this pattern : [dbtable].view.tmpl

products view page : products.view.tmpl
products create page : products.create.tmpl
products edit page : products.edit.tmpl
products delete page : products.delete.tmpl

Routes can use the same file depending how the template code is writen, for example :
products create & edit page : products.edit.tmpl (template code can handle both)

Pages without data connection / static pages : [pagename].[action].tmpl

page about : about.view.tmpl
page contact : contact.view.tmpl

  • Home Page
    Same rule like all the above pages

page home : home.view.tmpl

Basic Use

  • Edit configuration file,
#UseCache true/false 
#Read files for every request, use this option for debug and development, set to true on production server
UseCache: false

#EnableInfoLog true/false
#Enable information log in console window, set to false in production server
EnableInfoLog: true

#InfoFile "path.to.filename"
#Set info filename, direct info log to file instead of console window
InfoFile: ""

#ShowStackOnError true/false
#Set to true to see the stack error trace in web page error report, set to false in production server
ShowStackOnError: true

#ErrorFile "path.to.filename"
#Set error filename, direct error log to file instead of web page, set this file name in production server
ErrorFile: ""

#Server Settings
server:
  #Listening port
  port: 8080

  #Session timeout in hours 
  sessionTimeout: 24

  #Use secure session, set to tru in production server
  sessionSecure: true

#Database settings
database:
  #Database name
  dbname: "golang"

  #Database server/ip address
  server: "localhost"

  #Database user
  dbuser: "root"

  #Database password
  dbpass: ""
func main()

Create controller variable in your main.go file outside the func main() Controller must be accessible from all functions in main package

var c gomvc.Controller

  • Load Configuration file

cfg := gomvc.LoadConfig("./configs/config.yml")

  • Connect to database
db, err := gomvc.ConnectDatabase(cfg.Database.Dbuser, cfg.Database.Dbpass, cfg.Database.Dbname)
if err != nil {
	log.Fatal(err)
	return
}
defer db.Close()
  • Start web server
srv := &http.Server{
	Addr:    ":" + strconv.FormatInt(int64(cfg.Server.Port), 10),
	Handler: AppHandler(db, cfg),
}

fmt.Println("Web app starting at port : ", cfg.Server.Port)

err = srv.ListenAndServe()
if err != nil {
	log.Fatal(err)
}
main()
func main() {

	// Load Configuration file
	cfg := gomvc.LoadConfig("./config/config.yml")

	// Connect to database
	db, err := gomvc.ConnectDatabase(cfg.Database.Dbuser, cfg.Database.Dbpass, cfg.Database.Dbname)
	if err != nil {
		log.Fatal(err)
		return
	}
	defer db.Close()

	//Start Server
	srv := &http.Server{
		Addr:    ":" + strconv.FormatInt(int64(cfg.Server.Port), 10),
		Handler: AppHandler(db, cfg),
	}

	fmt.Println("Web app starting at port : ", cfg.Server.Port)

	err = srv.ListenAndServe()
	if err != nil {
		log.Fatal(err)
	}
}
AppHandler()
  • initialize the controller
  • load your template files into cache
  • initialize your models
  • register urls and actions

RegisterAction (route, next, action, model)
route : string "url"
next : string "url" (used after POST to redirect browser)
action : [
gomvc.ActionView View (GET) /
gomvc.ActionCreate Create (POST) /
gomvc.ActionUpdate Update (POST) /
gomvc.ActionDelete Delete (POST)
]
model : database gomvc.model object

func AppHandler(db *sql.DB, cfg *gomvc.AppConfig) http.Handler {

	// initialize controller
	c.Initialize(db, cfg)

	// load template files ... path : /web/templates
	// required : homepagefile & template file
	// see [template names] for details
	c.CreateTemplateCache("home.view.tmpl", "base.layout.html")

	// *** Start registering urls, actions and models ***

	// RegisterAction(url, next, action, model)
	// url = url routing path
	// next = redirect after action complete, use in POST actions if necessary
	// model = database model object for CRUD operations

	// home page : can have two urls "/" and "/home"
	c.RegisterAction("/", "", gomvc.ActionView, nil)
	c.RegisterAction("/home", "", gomvc.ActionView, nil)

	// create model for [products] database table
	// use the same model for all action in this example
	pModel := gomvc.Model{DB: db, PKField: "id", TableName: "products"}

	// view products ... / show all products || /products/view/{id} for one product
	c.RegisterAction("/products", "", gomvc.ActionView, &pModel)
	c.RegisterAction("/products/view/*", "", gomvc.ActionView, &pModel)

	// build create product action ... this url has two actions
	// #1 View page -> empty product form no redirect url (no next url required)
	// #2 Post form data to create a new record in table [products] -> then redirect to [next] url -> products page
	c.RegisterAction("/products/create", "", gomvc.ActionView, &pModel)
	c.RegisterAction("/products/create", "/products", gomvc.ActionCreate, &pModel)

	// build edit product actions ... this url has two actions
	// #1 View page with the product form -> edit form (no next url required)
	// #2 Post form data to update record in table [products] -> then redirect to [next] url -> products page
	c.RegisterAction("/products/edit/*", "", gomvc.ActionView, &pModel)
	c.RegisterAction("/products/edit/*", "/products", gomvc.ActionUpdate, &pModel)

	// build delete product actions ... this url has two actions
	// #1 View page with the product form -> edit form [locked] to confirm detetion (no next url required)
	// #2 Post form data to delete record in table [products] -> then redirect to [next] url -> products page
	c.RegisterAction("/products/delete/*", "", gomvc.ActionView, &pModel)
	c.RegisterAction("/products/delete/*", "/products", gomvc.ActionDelete, &pModel)

	// build about page ... static page, no table/model, no [next] url
	c.RegisterAction("/about", "", gomvc.ActionView, nil)

	// build contact page ... static page, no table/model, no [next] url
	c.RegisterAction("/contact", "", gomvc.ActionView, nil)

	// build contact page POST action ... static page, no table/model, no [next] url
	// Demostrating how to register a custom func to handle the http request/response using your oun code
	// and handle POST data and have access to database through the controller and model object
	c.RegisterCustomAction("/contact", "", gomvc.HttpPOST, nil, ContactPostForm)
	return c.Router
}
Custom Action func ContactPostForm()

Build a custom func to handle a specific action or url. This example handles the POST request from a contact form.

// Custom handler for specific page and action
func ContactPostForm(w http.ResponseWriter, r *http.Request) {

	//test : I have access to products model !!!
	fmt.Print("\n\n")
	fmt.Println("********** ContactPostForm **********")
	fmt.Println("Table Fields : ", c.Models["/products"].Fields)

	//read data from table products (Model->products) even if this is a POST action for contact page
	fmt.Print("\n\n")
	rows, _ := c.Models["/products"].GetRecords([]gomvc.Filter{}, 100)
	fmt.Println("Select Rows Example 1 : ", rows)

	//read data from table products (Model->products) even if this is a POST action for contact page
	fmt.Print("\n\n")
	id, _ := c.Models["/products"].GetLastId()
	fmt.Println("Select Rows Example 1 : ", id)

	//read data from table products (Model->products) with filter (id=1)
	fmt.Print("\n\n")
	var f = make([]gomvc.Filter, 0)
	f = append(f, gomvc.Filter{Field: "id", Operator: "=", Value: 1})
	rows, err := c.Models["/products"].GetRecords(f, 0)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Select Rows Example 2 : ", rows)

	//test : Print Posted Form fields
	fmt.Print("\n\n")
	fmt.Println("Form fields : ", r.Form)

	//test : Set session message
	c.GetSession().Put(r.Context(), "error", "Hello From Session")

	//redirect to homepage
	http.Redirect(w, r, "/", http.StatusSeeOther)

}

More Examples ...

Example 01 - basic use of gomvc, one table [products]

Example 02 - basic use of gomvc, two tables related [products]->[colors] (one-to-many relation)

Example 03 - gomvc Auth example, two tables related [products]->[colors] (one-to-many relation)

More examples comming soon ...

License

Copyright (c) 2020-present Kostas Dakanalis

Licensed under Apache-2.0

Documentation

Overview

Package gomvc is a Golang package easy to use and build almost any MVC Web App connected to MySql database with just a few steps. `gomvc` package requires a MySql Server up and running and a database ready to drive your web application.

Build a standard MVC (Model, View, Controller) style web app with minimum Golang code, like you use a classic MVC Framework. Many features, many ready to use functions, highly customizable, embeded log and error handling

#### MVC

``` (databse CRUD) (http req/resp)

Model <--------> Controller
    \            /
     \          /
      \        /
       \      /
        \    /
         View
 (text/template files)

```

#### Basic Steps * Edit the config file * Load config file `config.yaml` * Connect to MySql database * Write code to initialize your Models and Controllers * Write your standard text/Template files (Views) * Start your server and enjoy

#### More Examples Find mire examples in Readme.md file

Index

Constants

View Source
const (
	HttpGET  int = 0
	HttpPOST int = 1
)

HttpGET, HttpPOST constants are helping the use of the package when it comes to the type of request

Variables

View Source
var Session *scs.SessionManager

Session is the SessionManager that will work as a middleware.

Functions

func BuildQuery

func BuildQuery(queryType QueryType, fields []SQLField, table SQLTable, joins []SQLJoin, wheres []Filter, group string, order string, limit int64) (string, []interface{})

Build quey func

func ConnectDatabase

func ConnectDatabase(user string, pass string, dbname string) (*sql.DB, error)

ConnectDatabase

func FindInSlice

func FindInSlice(slice []string, value string) int

FindInSlice find a value in a slice and return the index

func InfoMessage

func InfoMessage(info string)

InfoMessage print/log an INFO message -> send to info logger

func InitHelpers

func InitHelpers(appcfg *AppConfig)

InitHelpers is the function to call in order to build the Helpers

func ServerError

func ServerError(w http.ResponseWriter, err error)

ServerError print/log a Server error -> send to error logger

Types

type Action

type Action int

Action defines the type of action to execute from a handler. ActionVew = return data to http client ActionCreate, ActionUpdate, ActionDelete = create, update, delete records from database, this action are more likeky to accompaned with an ActionView action so they return a result to the http client after the action

const (
	ActionView   Action = 0
	ActionCreate Action = 1
	ActionUpdate Action = 2
	ActionDelete Action = 3
)

type ActionRouting

type ActionRouting struct {
	URL       string
	NextURL   string
	NeedsAuth bool
	IsWebHook bool
}

ActionRouting helps the router to have the routing information about the URL, the NextURL, if the route needs authentication or if it is a web hook (web hook can have POST data without midleware CSRF check)

type AppConfig

type AppConfig struct {
	UseCache         bool
	Server           ServerConf
	Database         DatabaseConf
	EnableInfoLog    bool
	ShowStackOnError bool
}

func ReadConfig

func ReadConfig(filePath string) *AppConfig

func (*AppConfig) GetValue

func (*AppConfig) GetValue(key string) interface{}

type AuthCondition

type AuthCondition struct {
	Field    string
	Operator string
	Value    string
}

AuthCondition is the struct for the ExtraConditions field in the AuthObject struct.

type AuthObject

type AuthObject struct {
	Model             Model
	UsernameFieldName string
	PasswordFieldName string
	HashCodeFieldName string
	ExpTimeFieldName  string
	SessionKey        string
	ExpireAfterIdle   time.Duration
	ExtraConditions   []AuthCondition

	LoggedInMessage  string
	LoginFailMessage string
	// contains filtered or unexported fields
}

AuthObject is a struct that holds all the information to perform a correct authentication against the user table in the database.

var Auth AuthObject

Auth is the authentication object

func (*AuthObject) CheckPasswordHash

func (a *AuthObject) CheckPasswordHash(password, hash string) bool

CheckPasswordHash compares password and hash for Authentication using bcrypt.

func (*AuthObject) GetExpirationFromNow

func (a *AuthObject) GetExpirationFromNow() time.Time

GetExpirationFromNow returns the expiration time from now.

func (*AuthObject) HashPassword

func (a *AuthObject) HashPassword(password string) (string, error)

HashPassword create a password hash

func (*AuthObject) IsSessionExpired

func (a *AuthObject) IsSessionExpired(r *http.Request) (bool, error)

IsSessionExpired checks authentication, get cookie value and check against user record in database

func (*AuthObject) KillAuthSession

func (a *AuthObject) KillAuthSession(w http.ResponseWriter, r *http.Request) error

KillAuthSession kills the auth session by reseting the expiration time in user record in database

func (*AuthObject) TokenGenerator

func (a *AuthObject) TokenGenerator() string

TokenGenerator is the random token generator

type Controller

type Controller struct {
	DB                      *sql.DB
	Models                  map[string]*Model
	TemplateCache           map[string]TemplateObject
	TemplateLayout          string
	TemplateHomePage        string
	UnderConstructionLayout string
	UnderConstructionPage   string
	Options                 map[string]controllerOptions
	Router                  *chi.Mux
	Config                  *AppConfig
}

Controller is the controller struct, contains the models, the templates, the web layout, the home page, the under construction page the controller options for each route, the router itself and the config struct.

func (*Controller) AddTemplateData

func (c *Controller) AddTemplateData(td TemplateData, r *http.Request) TemplateData

AddTemplateData adds data for templates, the data will be available in the view to build the web page before response.

func (*Controller) CreateTemplateCache

func (c *Controller) CreateTemplateCache(homePageFileName string, layoutTemplateFileName string) error

CreateTemplateCache loads the template files and creates a cache of templates in controller.

func (*Controller) GetAuthObject

func (c *Controller) GetAuthObject() *AuthObject

GetAuthObject return Authobject

func (*Controller) GetSession

func (c *Controller) GetSession() *scs.SessionManager

GetSession return session manager

func (*Controller) GetTemplate

func (c *Controller) GetTemplate(page string) (*template.Template, error)

GetTemplate return a single template from template cache

func (*Controller) GetUnderConstructionTemplate

func (c *Controller) GetUnderConstructionTemplate(page string) (*template.Template, error)

GetUnderConstructionTemplate get the under construction page

func (*Controller) Initialize

func (c *Controller) Initialize(db *sql.DB, cfg *AppConfig)

Initialize from this function we pass a pointer to db connection and a pointer to appconfig struct

func (*Controller) RegisterAction

func (c *Controller) RegisterAction(route ActionRouting, action Action, model *Model)

RegisterAction register controller action - route, next, action and model RegisterAction, RegisterAuthAction, RegisterCustomAction are the most important functions in the gomvc package all functions are responsible for processing requests and generating responses. RegisterAction is used to register one of the pre defined actions View, Create, Update, Delete

func (*Controller) RegisterAuthAction

func (c *Controller) RegisterAuthAction(authURL string, nextURL string, model *Model, authObject AuthObject)

RegisterAuthAction register controller action - route, next, action and model is used to register the authentication actions

func (*Controller) RegisterCustomAction

func (c *Controller) RegisterCustomAction(route ActionRouting, method int, model *Model, f http.HandlerFunc)

RegisterCustomAction register controller action - route, next, action and model RegisterAction, RegisterAuthAction, RegisterCustomAction are the most important functions in the gomvc package all functions are responsible for processing requests and generating responses. RegisterCustomAction is used to register any custom action that doesn't fit the pre defined actions View, Create, Update, Delete

func (*Controller) View

View provides a set of methods (e.g. render()) for rendering purpose.

type DatabaseConf

type DatabaseConf struct {
	Server string
	Dbname string
	Dbuser string
	Dbpass string
}

type Filter

type Filter struct {
	Field    string
	Operator string
	Value    interface{}
	Logic    string
}

type JoinType

type JoinType string
const (
	ModelJoinInner JoinType = "INNER"
	ModelJoinLeft  JoinType = "LEFT"
	ModelJoinRight JoinType = "RIGHT"
)

type Model

type Model struct {
	DB           *sql.DB
	PKField      string
	TableName    string
	OrderString  string
	Fields       []string
	Labels       map[string]string
	Relations    []Relation
	DefaultQuery string
	// contains filtered or unexported fields
}

func (*Model) AddRelation

func (m *Model) AddRelation(db *sql.DB, tableName string, PKField string, keys SQLKeyPair, join_type JoinType, result_style ResultStyle)

Add Foreign table (model)

func (*Model) AssignLabels

func (m *Model) AssignLabels(labels map[string]string)

func (*Model) Delete

func (m *Model) Delete(id string) (bool, error)

Execute delete query

func (*Model) Execute

func (m *Model) Execute(q string, values ...interface{}) ([]ResultRow, error)

Execute custon query

func (*Model) GetLastId

func (m *Model) GetLastId() (int64, error)

Get last id from Table

func (*Model) GetRecords

func (m *Model) GetRecords(filters []Filter, limit int64) ([]ResultRow, error)

Query table with filters

func (*Model) InitModel

func (m *Model) InitModel(db *sql.DB, tableName string, PKField string) error

Pass initial Parammeters

func (*Model) Instance

func (m *Model) Instance() Model

Get current instance

func (*Model) Label

func (m *Model) Label(field string) string

func (*Model) Save

func (m *Model) Save(fields []SQLField) (bool, error)

Execute save query

func (*Model) Update

func (m *Model) Update(fields []SQLField, id string) (bool, error)

Execute update query

type QueryType

type QueryType string
const (
	QueryTypeInsert QueryType = "c"
	QueryTypeSelect QueryType = "r"
	QueryTypeUpdate QueryType = "u"
	QueryTypeDelete QueryType = "d"
)

type Relation

type Relation struct {
	Join          SQLJoin
	Foreign_model Model
	ResultStyle   ResultStyle
}

type RequestObject

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

RequestObject is a struct builded from the http request, holds the url data in a convinient way.

type ResultRow

type ResultRow struct {
	Values []interface{}
	Fields []string

	Subresult []ResultRow
	// contains filtered or unexported fields
}

func (*ResultRow) GetFieldIndex

func (r *ResultRow) GetFieldIndex(name string) int

type ResultStyle

type ResultStyle int
const (
	ResultStyleFullresult ResultStyle = 0
	ResultStyleSubresult  ResultStyle = 1
)

type SQLField

type SQLField struct {
	FieldName string
	Value     interface{}
}

type SQLJoin

type SQLJoin struct {
	Foreign_table string
	Foreign_PK    string
	KeyPair       SQLKeyPair
	Join_type     JoinType
}

type SQLKeyPair

type SQLKeyPair struct {
	LocalKey   string
	ForeignKey string
}

type SQLTable

type SQLTable struct {
	TableName string
	PKField   string
}

type ServerConf

type ServerConf struct {
	Port          int
	SessionSecure bool
}

type TemplateData

type TemplateData struct {
	Model        Model
	Result       []ResultRow
	URLParams    map[string][]interface{}
	CustomValues map[string][]interface{}
	CSRFToken    string
	Flash        string
	Warning      string
	Error        string
}

TemplateData is used to provide all data to the template engine to build the webpage.

type TemplateObject

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

TemplateObject is the template struct, holds the filename and the template object.

Jump to

Keyboard shortcuts

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