Haste Golang Light Weight Web Framework
Here are the tutorials for Golang Haste Framework
Before step into the framework, lets better understand what is Golang and why do we need a framework.
Golang is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. Go is syntactically similar to C, but with memory safety, garbage collection, structural typing, and CSP-style concurrency.
Golang has routes inbuild where in other languages you may find this in some framework like for example in Nodejs you will not find inbuild routes, but in Express framework which is built over Nodejs has routes facilities.
In Golang even we have template engine for rendering HTML and binding variables and loops over it, which again you won’t find in other languages directly you might have to use blade template, or jade template etc. Then if everything is inbuild in Golang why do we need a framework, well basically everyone does not have the same standard code of writing. We might need to develop middlewares and even some extra concurrency to do the task faster.
Here in Haste framework, we have inbuild middlewares, which you might need to validate session for example, in every request you receive. In this framework, we have used goroutines and even context module using channels to do the task faster and send the message from one module to other using channels. Future scope of this framework, we will have ODM for MongoDB and other NoSQL databases, ORM for SQL databases, inbuild connectivity with HDFS, MongoDB, SQL, Cassandra, Redis etc.
We have on more feature in this framework is the term we call projection. Suppose you have 5 modules in UI and need to call 5 REST APIs for that to get the message and then populate in the UI, rather than calling 5 APIs separately we will send 1 request with 5 method name and request inside the payload for example.
{
“Login”:{
“username”:”sudeep.dasgupta”,
“password”:”kaihiwatari”
},
“GetProfile”:{},
“SchemesMaster”:{
“category”:”EQUITY”
}
}
This payload has three methods one is login, the second one is GetProfile and last is SchemeMaster now rather than calling three Apis a single request was send along with the method name and all the three response is received. Now this method a drawback, it currently only supports JSON payload along with content-type: application/json.
One more thing about this projection is that you can send a response using http/1.1 but it will send response only after all the responses are prepared in the backend. But if you use WebSocket or http/2 streams then it will send the message only when the single method response is prepared and will eventually it will push all other after their message is prepared one by one.
This projection is actually inspired by Google GRPC, apache thrift and GraphQL.
To get the complete source code visit: https://github.com/pounze/go_haste
Bellow are the small snippet of creating routes middlewares and projection.
- Server.go page for initializing webserver
package main
import(
"cns"
"Web"
"net/http"
"fmt"
)
func main(){
httpApp := cns.Http{}
Web.Routes()
go func(){
defer cns.CreateHttpServer(":8000")
}()
defer cns.CreateHttpStreaming(":8100", "./ssl/https-server.crt","./ssl/https-server.key", "/streaming")
// we can also create https server
defer cns.CreateHttpsServer(":8300", "./ssl/https-server.crt","./ssl/https-server.key", "/")
// for http/2 server we write the following code
defer cns.CreateHttp2Server(":8300", "./ssl/https-server.crt","./ssl/https-server.key", "/")
defer httpApp.DefaultMethod(func(req *http.Request,res http.ResponseWriter){
res.Header().Set("Name", "Sudeep Dasgupta")
res.Header().Set("Content-Type", "application/json")
res.Header().Set("Access-Control-Allow-Origin", "*")
res.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
fmt.Println("Default header executed")
})
}
Here we have created 2 web servers 1 in http/1.1 and one in Http Streaming for projection. Then we have called a DefaultMethod which will be triggered whenever a new request is received. It can be used to set CORRS headers etc.
We write all routes inside the Web/RouteList.go
import(
"cns"
"fmt"
"net/http"
)
func Routes(){
httpApp := cns.Http{}
// for projection api create schema
httpApp.CreateSchema(map[string]cns.Projection{
"Login": cns.Projection{
sample.Login,
10,
},
"GetProfile": cns.Projection{
sample.GetProfile,
10,
},
});
// set route path for projection schema add middleware method to it
httpApp.SetRoutePath("/").Middlewares(func(req *http.Request,res http.ResponseWriter,done chan bool){
fmt.Println("middleware worked")
done <- true
})
// projection api for socket support
httpApp.SetSocketRoutePath("/realtime").Middlewares(func(req *http.Request,res http.ResponseWriter,done chan bool){
fmt.Println("middleware worked")
done <- true
})
// block directories to get access
httpApp.BlockDirectories([]string{"/UserView/img/","/UserView/js/"})
hm := map[string]string{
"$id":"[0-9]{2}",
"$name":"[a-z]+",
}
// to save file in case of multipart form data
httpApp.SaveFile(w http.ResponseWriter, file multipart.File, path string, fileChan chan bool)
// url matching using regular expression and calling multiple middleware with chaining
httpApp.Post("/$id/$name[\\/]*",func(req *http.Request,res http.ResponseWriter){
fmt.Println("method invoked")
fmt.Println(req.URL.Query().Get("$name"))
fmt.Fprintf(res, "Successfully Done")
}).Middlewares(func(req *http.Request,res http.ResponseWriter,done chan bool){
err := req.ParseMultipartForm(200000)
if err != nil {
fmt.Println("Unable to parse form data")
return
}
_,handle,_ := req.FormFile("name")
fmt.Println(handle)
done <- true
}).Middlewares(func(req *http.Request,res http.ResponseWriter,done chan bool){
fmt.Println("working both")
done <- true
}).Where(hm)
// calling Get request method same POST, PUT and DELETE available
httpApp.Get("/",func(req *http.Request,res http.ResponseWriter){
//cns.Push(res,"/UserView/js/test.js")
stat,_,result := cns.Authorization(req,res,"Enter username and password to Authenticate")
if stat{
fmt.Println(result)
http.ServeFile(res, req, "src/views/index.html")
}else{
fmt.Fprintf(res, "Unauthorized")
}
})
// TO call global middleware
httpApp.GlobalMiddleWares(func(req *http.Request,res http.ResponseWriter,done chan bool){
fmt.Println("working both")
done <- true
})
// creating try catch block to handle exception
cns.Block{
Try:func(){
fmt.Println("I tried")
cns.Throw("ohhh")
fmt.Println("Working")
},
Catch:func(e cns.Exception){
fmt.Println("caught exception",e)
},
Finally:func(){
fmt.Println("Finally")
},
}.Do()
}
For the Config.go, it is inside the cns/Config.go
There are lots of framework like gin, buffalo but you can benchmark this Haste with them and you may love it as its simple, fast and lightweight. We will try to improve the documentation better. Till then happy coding.