Iris microservice framework_ golang web Framework_ Full sample Demo

Iris introduction

Iris is a framework used to develop web applications in Go language. The framework supports writing once and running with minimum machine power anywhere, such as Android, ios, Linux and Windows. The framework only needs an executable service to run on the platform.

Iris framework is familiar to developers with its simple and powerful api. Iris not only provides developers with very simple access, but also supports MVC. In addition, it is easy to build micro services with iris.

On the official website of iris framework, it is known as the fastest Go back-end development framework. On iris's website document, some features and framework features of the framework are listed as follows:

Iris characteristics
  • Focus on high performance
  • Simple and fluent API
  • High scalability
  • Powerful routing and middleware ecosystem
  • Building restful APIs using iris's unique expressionist path interpreter
  • Dynamic path parameterization or wildcard routing does not conflict with static routing
  • Use the redirect option to remove trailing slashes from the URL
  • It's easy to use virtual hosts and subdomains
  • Grouping API s and static or even dynamic subdomains
  • net / http and Negroni like handlers via iris Fromstd compatible
  • Define the processing function for any Http request error
  • Support transaction and rollback
  • Support response caching
  • Use simple functions to embed resources and be compatible with go bindata
  • mvc
  • context
  • Highly scalable rendering (currently supports markdown,json,xml, JSON, etc.)
  • Text binder and convenient function of sending HTTP response
  • Limit request body
  • Provide static resources or embedded assets
  • Localize i18N
  • Compression (Gzip is built-in)
  • Authentication
  • Basic Authentication
  • OAuth, OAuth2 (support more than 27 popular websites)
  • JWT * server
  • When providing services through TLS, automatically install and provide services from https://letsencrypt.org Certificate of
  • The default is off
  • Register on shutdown, error, or interrupt events
  • Connect multiple servers, fully compatible with net / HTTP #
  • View system Five templates are supported, which are implicitly and fully compatible with html/template
  • Websocket library, whose API is similar to http://socket.io [you can still use your favorite if you like]
  • Hot restart
  • Typescript integration + Web IDE

Official source code address: https://github.com/kataras/iris

Iris web microservice framework example

Overall function

  • Integrated aiwutech FileLogger logs are cut by day and output to different log files by level
  • Integrated redis
  • Integrating mysql
  • Read etcd configuration
  • Exception handling, global exception handling
  • Interceptor print request and response parameters
  • Front end html integration
  • wait

Download iris dependency package
go get -u github.com/kataras/iris
main.go project entrance

init method: initialize relevant configurations, with notes
main method: start Iris service

package main

import (
	. "web-demo/config"
	. "web-demo/log"
	. "web-demo/redis"
	. "web-demo/db"
	_ "web-demo/handler"
	"web-demo/web"
	"flag"
	"fmt"
	"time"
)

var showVersion = flag.Bool("v", true, "print version")

func init(){
	//Call flag Parse()
	flag.Parse()

	//Initialize profile
	ConfigRead()

	//Initialize log
	LogInit()

	//Initialize redis
	RedisInit(Cfg.RedisAddr,0 , Cfg.RedisPassword, Cfg.RedisMaxConn)

	//Initialize mysql
	SqlDBInit(&SqlDBParam{Cfg.MysqlHost, Cfg.MysqlPort, Cfg.MysqlUser, Cfg.MysqlPwd,
	Cfg.MysqlDb})
}

func main() {
	if *showVersion {
		//This date is a date written dead. If you don't know this date, you can't format it correctly
		//It is said to be the day of the birth of go
		version := fmt.Sprintf("%s %s@%s", "web-demo", "1.0", time.Now().Format("2006-01-02 15:04:05"))
		fmt.Println(version)
	}

	Log.Info("start server...")

	//Listening port
	Log.Info("listen on :%s", Cfg.ListenPort)
	web.RunIris(Cfg.ListenPort)
}


AccessLogMiddleware.go middleware interceptor

Add request header in interceptor
Print the request parameters and response parameters to the log file

package web

import (
	. "web-demo/util/threadlocal"
	. "web-demo/log"
	"github.com/kataras/iris"
	. "github.com/jtolds/gls"
	"strconv"
	"time"
)

func init() {
	RegisterPreMiddleware(accessLogMiddleware{})
}

type accessLogMiddleware struct {
	// your 'stateless' fields here
}

func (m accessLogMiddleware) Serve(ctx *iris.Context) {
	//check header
	//request id
	requestId := ctx.RequestHeader("X-Web-Demo-RequestId")
	if requestId == "" {
		requestId = strconv.FormatInt(time.Now().UnixNano(), 10)
	}

	//access log
	AccessLog.Info(requestId + "\t" + ctx.RequestIP() + "\t" + string(ctx.RequestURI()))

	//response requestId
	ctx.Response.Header.Add("X-Web-Demo-RequestId", requestId)

	//do chian
	Mgr.SetValues(Values{Rid: requestId}, func() {
		ctx.Next()
	})

	//rrlog
	RRLog.Info(requestId + "\t" + "-RequestIP:==" + ctx.RequestIP())
	RRLog.Info(requestId + "\t" + "-RequestP:==" + string(ctx.RequestPath(true)))
	RRLog.Info(requestId + "\t" + "-RequestD:==" + string(ctx.Request.Body()))
	RRLog.Info(requestId + "\t" + "-Response:==" + string(ctx.Response.Body()))
}


logger.go log definition and configuration
package log

import (
	"flag"
	"github.com/aiwuTech/fileLogger"
	"os"
	. "web-demo/util/threadlocal"
	"web-demo/config"
)

var Log Logger
var ErrorLog Logger
var AccessLog Logger
var RRLog Logger
var InnerRRLog Logger

type Logger interface {
	Trace(format string, params ...interface{})
	Info(format string, params ...interface{})
	Warn(format string, params ...interface{})
	Error(format string, params ...interface{})
}

type CustomedLogger struct{
	MyLogger Logger
}
func (cl CustomedLogger)Trace(format string, params ...interface{}){
	cl.MyLogger.Trace(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Info(format string, params ...interface{}){
	cl.MyLogger.Info(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Warn(format string, params ...interface{}){
	cl.MyLogger.Warn(cl.resetFormat(format), params)
}
func (cl CustomedLogger)Error(format string, params ...interface{}){
	cl.MyLogger.Error(cl.resetFormat(format), params)
}
func (cl CustomedLogger)resetFormat(format string) string{
	logstr := format
	if rid, ok := Mgr.GetValue(Rid); ok {
		logstr = rid.(string) + " - " + logstr
	}
	return logstr
}

func LogInit() {
	logPath := config.Cfg.LogPath
	if (len(logPath) == 0) {
		logPath = "/Users/liang/ideaWorkspace/go/src/web-demo/logs/web-demo"
	}

	flag.Parse()
	if !isExist(logPath) {
		os.Mkdir(logPath, 0755)
	}

	logger := fileLogger.NewDailyLogger(logPath, "root.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
	Log = CustomedLogger{MyLogger: logger}

	errorLog := fileLogger.NewDailyLogger(logPath, "error.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
	ErrorLog = CustomedLogger{MyLogger: errorLog}

	accessLog := fileLogger.NewDailyLogger(logPath, "access.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
	AccessLog = CustomedLogger{MyLogger: accessLog}

	rRLog := fileLogger.NewDailyLogger(logPath, "rr.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
	RRLog = CustomedLogger{MyLogger: rRLog}

	innerRRLog := fileLogger.NewDailyLogger(logPath, "inner_rr.log", "", fileLogger.DEFAULT_LOG_SCAN, fileLogger.DEFAULT_LOG_SEQ)
	InnerRRLog = CustomedLogger{MyLogger: innerRRLog}
}

func isExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}


mysql.go mysql initialization connection
package db

import (
	. "web-demo/log"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	. "web-demo/config"
)

var Mysql *gorm.DB

type SqlDBParam struct {
	Ip       string
	Port     int
	User     string
	Pw       string
	Database string
}
// mysql initialization file
func SqlDBInit(param *SqlDBParam) {
	Log.Info("init mysql...")
	param_s := fmt.Sprintf(
		"%v:%v@tcp(%v:%v)/%v?parseTime=True&loc=Local",
		param.User,
		param.Pw,
		param.Ip,
		param.Port,
		param.Database,
	)
	Log.Info("mysql param: %s", param_s)

	db, err := gorm.Open("mysql", param_s)
	if err != nil {
		Log.Error("open mysql error: %v", err)
		panic(err)
	}
	db.DB().SetMaxIdleConns(Cfg.MysqlMaxConn)
	db.SingularTable(true)
	db.LogMode(true)

	Mysql = db
	Log.Info("init mysql end.")
}

redis.go redis initialization and common operation methods
package redis

import (
	. "web-demo/log"
	"github.com/garyburd/redigo/redis"
	"time"
)

var (
	redisPool *redis.Pool
)

const (
	maxIdle     = 500
	idleTimeout = 0 * time.Second
	wait        = true
)

//Init
//eg: RedisInit("127.0.0.1:6379", 0, "pwd", 8)
func RedisInit(server string, db int, password string, maxConn int) {
	maxActive := maxConn

	//Make a pool object
	redisPool = &redis.Pool{
		// Maximum number of idle connections in the pool.
		MaxIdle: maxIdle,

		// Maximum number of connections allocated by the pool at a given time.
		// When zero, there is no limit on the number of connections in the pool.
		MaxActive: maxActive,

		// Close connections after remaining idle for this duration. If the value
		// is zero, then idle connections are not closed. Applications should set
		// the timeout to a value less than the server's timeout.
		IdleTimeout: idleTimeout,

		// If Wait is true and the pool is at the MaxActive limit, then Get() waits
		// for a connection to be returned to the pool before returning.
		Wait: wait,

		// Dial is an application supplied function for creating and configuring a
		// connection.
		//
		// The connection returned from Dial must not be in a special state
		// (subscribed to pubsub channel, transaction started, ...).
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				return nil, err
			}
			return c, nil
		},
		// TestOnBorrow is an optional application supplied function for checking
		// the health of an idle connection before the connection is used again by
		// the application. Argument t is the time that the connection was returned
		// to the pool. If the function returns an error, then the connection is
		// closed.
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
	}
	Log.Info("redis[%v %v] init ok", server, db)
}

......

Handler note that Iris will automatically scan the handler package name

If there are multiple packages, such as user and html in the demo, iris cannot be scanned at this time
You need to add a public file in the handler package to import the two packages, as shown below

package handler

import (
	_ "web-demo/handler/html"
	_ "web-demo/handler/user"
)

Other functions will not be introduced in detail. Please see the source code

Web demo run
#Start project
go run main.go 
#The following print indicates that port 8080 is successfully started
listen on :8080

Browser access:
http://127.0.0.1:8080/webdemo/html/v1/passenger/login.md
Display login MD file content

http://127.0.0.1:8080/webdemo/html/v1/index
Display index HTML content

Demo source code address: https://github.com/golang-example/web-demo

Keywords: Go iris

Added by Xajel on Sat, 29 Jan 2022 00:37:05 +0200