grapes is a minimalistic router written in golang
provides the ability to handle parameterized requests, send files, serve static requests, and more
- Installation
- Example
- Tree structure
- Context
- Parameters:
- Serving files:
- Forms:
- Additional:
To use grapes just create .mod file and add package
go get -u github.com/Rosto4eks/grapes
package main
import "github.com/Rosto4eks/grapes"
func main() {
// create new router
r := grapes.NewRouter()
r.Get("/", func(ctx grapes.Context) {
ctx.SendString("Hello World!")
})
r.Get("/Home", func(ctx grapes.Context) {
ctx.SendJson(grapes.Obj{
"title": "Home",
"id": 1,
})
})
r.Post("/Home", func(ctx grapes.Context) {
id := ctx.GetQueryParam("Id")
ctx.SendJson(grapes.Obj{
"id": id,
})
})
// start listening at port 80
r.Run(80)
}
GET / -> "Hello World!"
GET /Home -> {"id": 1,"title": "Home"}
POST /Home?id=1 -> {"id": 1}
The router applies tree structure which allows to use parameterized requests like /*, /:id
tree consists of nodes, each node has Handlers and Childrens (next nodes)
when the request comes, router splits the url and searches into tree suitable node
- /
├ /*
├ /:id
| ├ /name
| └ /*
└ /Home
├ /info
└ /:other
Context is the superstructure over http.ResponseWriter and http.Request
it also provides some additional functionality for processing requests and sending responses, like sending JSON, files as response, extarcting parameters from request url
from
func (w http.ResponseWriter, r *http.Request) {
...
}
to
func(ctx grapes.Context) {
...
})
symbol * means, that router will handle any request with any part instead of symbol *
package main
import "github.com/Rosto4eks/grapes"
func catchAll(ctx grapes.Context) {
ctx.SendJson(grapes.Obj{
"title": "Home",
})
}
func catchInfo(ctx grapes.Context) {
ctx.SendJson(grapes.Obj{
"title": "Info",
})
}
func main() {
r := grapes.NewRouter()
r.Get("/*", catchAll)
r.Get("/*/Info/*", catchInfo)
r.Run(80)
}
/ -> 404 page not found
/credits -> {"title": "Home"}
/Home -> {"title": "Home"}
/Home/golang -> 404 page not found
/Home/Info -> 404 page not found
/Home/Info/github -> {"title": "Info"}
/Home/Info/chess -> {"title": "Info"}
/Home/Info/chess/queen -> 404 page not found
They are like catch-all params, but you can extract param value from url
function ctx.NamedParam(param) will return it
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/:id", func (ctx grapes.Context) {
id := ctx.NamedParam("id")
ctx.SendJson(grapes.Obj{
"id": id,
})
})
r.Get("/:id/:name", func (ctx grapes.Context) {
id := ctx.NamedParam("id")
name := ctx.NamedParam("name")
ctx.SendJson(grapes.Obj{
"id": id,
"name": name,
})
})
r.Run(80)
}
/ -> 404 page not found
/0x3DE3E -> {"id": "0x3DE3E"}
/0x3DE3E/Rosto4eks -> {"id": "0x3DE3E", "name": "Rosto4eks"}
/0x3DE3E/Rosto4eks/info -> 404 page not found
quoery params can be obtained using the function ctx.GetQueryParam(param)
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/Home", func (ctx grapes.Context) {
id := ctx.GetQueryParam("id")
ctx.SendJson(grapes.Obj{
"id": id,
})
})
r.Run(80)
}
/Home?id=1 -> {"id": "1"}
To send file, use function ctx.SendFile(path)
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/", func (ctx grapes.Context) {
ctx.SendFile("public/home.html")
})
r.Run(80)
}
To serve static files, use function router.Static(path, pattern)
pattern must start with '/' symbol
The example below shows how to use html with css (path in link to css will look like "/public/css/home.css")
Folder structure:
main.go
public
├ home.html
└ css
└ home.css
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Static("public", "/public")
r.Get("/", func (ctx grapes.Context) {
ctx.SendFile("public/home.html")
})
r.Run(80)
}
To send html with parameters, use ctx.Template(path, data)
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/", func(ctx grapes.Context) {
ctx.Template("t.html", grapes.Obj{
"Name": "Rosto4eks",
"Id": 1337,
})
})
r.Run(80)
}
t.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{{ .Name }} : {{ .Id }}
</body>
</html>
html form wich will be used in the next 2 examples
<form action="/" method="post" enctype="multipart/form-data">
<input name="name" type="text">
<input name="password" type="text">
<input name="file" type="file">
<input type="submit">
</form>
To parse values from form, use ctx.GetFormValue(key)
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Static("public", "/public")
r.Get("/", func (ctx grapes.Context) {
ctx.SendFile("public/home.html")
})
r.Post("/", func(ctx grapes.Context) {
name, _ := ctx.GetFormValue("name")
password, _ := ctx.GetFormValue("password")
ctx.SendJson(grapes.Obj{
"name":name,
"password":password,
})
})
r.Run(80)
}
To parse form file, use ctx.GetFormFile(key)
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Static("public", "/public")
r.Get("/", func (ctx grapes.Context) {
ctx.SendFile("public/home.html")
})
r.Post("/", func(ctx grapes.Context) {
file, header, _ := ctx.GetFormFile("file")
ctx.SendJson(grapes.Obj{
"fileName": header.Filename,
"fileSize": header.Size,
})
})
r.Run(80)
}
router.HttpNotFound is the build-in handler wich provides processing unhandled routes, also you can change this fuction:
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.HttpNotFound = func(ctx grapes.Context) {
ctx.SendString("Oops! Page not found.")
}
r.Get("/", func (ctx grapes.Context) {
ctx.SendString("Hello")
})
r.Run(80)
}
/ -> "Hello"
/Home -> "Oops! Page not found."
/Home/Info -> "Oops! Page not found."
point allows you to create nodes for more comfortable using
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/", func(ctx grapes.Context) {
ctx.SendString("/home")
})
p := r.Point("/info/credits")
p.Get("/:id", func(ctx grapes.Context) {
ctx.SendString(ctx.GetNamedParam("id"))
})
p.Get("/all", func(ctx grapes.Context) {
ctx.SendString("228")
})
r.Run(80)
}
/ -> "home"
/info/credits/1337 -> "1337"
/info/credits/all -> "228"
redirect allows you to redirect incoming requests
package main
import "github.com/Rosto4eks/grapes"
func main() {
r := grapes.NewRouter()
r.Get("/", func(ctx grapes.Context) {
ctx.SendString("moo")
})
r.Get("/meow", func(ctx grapes.Context) {
ctx.Redirect("/")
})
r.Run(80)
}
/meow -> "moo"