-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
gitlayzer
committed
Mar 24, 2024
1 parent
8b67154
commit 60fd4cf
Showing
11 changed files
with
490 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,17 @@ | ||
![logo](./img/logo.png) | ||
# Gee API Framework | ||
|
||
Gee API Framework encapsulates the net/http framework, making it easier and faster for us to write backend APIs | ||
|
||
**Gee has the following characteristics** | ||
- Fast | ||
- Zero allocation router | ||
- Middleware support | ||
- Routes grouping | ||
- Extendable | ||
|
||
## Get Started | ||
|
||
### Prerequisites | ||
|
||
- **[Go](https://go.dev/)**: any one of the **three latest major** [releases](https://go.dev/doc/devel/release) (we test it with these). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package gee | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
) | ||
|
||
type H map[string]interface{} | ||
|
||
type Context struct { | ||
Writer http.ResponseWriter | ||
Request *http.Request | ||
Path string | ||
Method string | ||
Params map[string]string | ||
StatusCode int | ||
handlers []HandlerFunc | ||
index int | ||
} | ||
|
||
func NewContext(w http.ResponseWriter, req *http.Request) *Context { | ||
return &Context{ | ||
Path: req.URL.Path, | ||
Method: req.Method, | ||
Request: req, | ||
Writer: w, | ||
index: -1, | ||
} | ||
} | ||
|
||
func (c *Context) Next() { | ||
c.index++ | ||
s := len(c.handlers) | ||
for ; c.index < s; c.index++ { | ||
c.handlers[c.index](c) | ||
} | ||
} | ||
|
||
func (c *Context) Fail(code int, err string) { | ||
c.index = len(c.handlers) | ||
c.JSON(code, H{"message": err}) | ||
} | ||
|
||
func (c *Context) Param(key string) string { | ||
value, _ := c.Params[key] | ||
return value | ||
} | ||
|
||
func (c *Context) PostForm(key string) string { | ||
return c.Request.FormValue(key) | ||
} | ||
|
||
func (c *Context) Query(key string) string { | ||
return c.Request.URL.Query().Get(key) | ||
} | ||
|
||
func (c *Context) Status(code int) { | ||
c.StatusCode = code | ||
c.Writer.WriteHeader(code) | ||
} | ||
|
||
func (c *Context) SetHeader(key string, value string) { | ||
c.Writer.Header().Set(key, value) | ||
} | ||
|
||
func (c *Context) String(code int, format string, values ...interface{}) { | ||
c.SetHeader("Content-Type", "text/plain") | ||
c.Status(code) | ||
c.Writer.Write([]byte(fmt.Sprintf(format, values...))) | ||
} | ||
|
||
func (c *Context) JSON(code int, obj interface{}) { | ||
c.SetHeader("Content-Type", "application/json") | ||
c.Status(code) | ||
encoder := json.NewEncoder(c.Writer) | ||
if err := encoder.Encode(obj); err != nil { | ||
http.Error(c.Writer, err.Error(), 500) | ||
} | ||
} | ||
|
||
func (c *Context) Data(code int, data []byte) { | ||
c.Status(code) | ||
c.Writer.Write(data) | ||
} | ||
|
||
func (c *Context) HTML(code int, html string) { | ||
c.SetHeader("Content-Type", "text/html") | ||
c.Status(code) | ||
c.Writer.Write([]byte(html)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package gee | ||
|
||
import "os" | ||
|
||
func IsDebug() bool { | ||
if os.Getenv("GEE_MODE") == "debug" { | ||
return false | ||
} else if os.Getenv("GEE_MODE") == "release" { | ||
return true | ||
} else { | ||
return false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package gee | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
type HandlerFunc func(ctx *Context) | ||
|
||
type RouterGroup struct { | ||
prefix string | ||
middlewares []HandlerFunc | ||
parent *RouterGroup | ||
engine *Engine | ||
} | ||
|
||
type Engine struct { | ||
*RouterGroup | ||
router *router | ||
groups []*RouterGroup | ||
} | ||
|
||
func New() *Engine { | ||
engine := &Engine{router: newRouter()} | ||
engine.RouterGroup = &RouterGroup{engine: engine} | ||
engine.groups = []*RouterGroup{engine.RouterGroup} | ||
return engine | ||
} | ||
|
||
func Default() *Engine { | ||
engine := New() | ||
engine.Use(Logger(), Recovery(), Server()) | ||
return engine | ||
} | ||
|
||
func (group *RouterGroup) Group(prefix string) *RouterGroup { | ||
engine := group.engine | ||
newGroup := &RouterGroup{ | ||
prefix: group.prefix + prefix, | ||
parent: group, | ||
engine: engine, | ||
} | ||
engine.groups = append(engine.groups, newGroup) | ||
return newGroup | ||
} | ||
|
||
func (group *RouterGroup) Use(middlewares ...HandlerFunc) { | ||
group.middlewares = append(group.middlewares, middlewares...) | ||
} | ||
|
||
func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) { | ||
pattern := group.prefix + comp | ||
fmt.Println(Logo) | ||
|
||
if !IsDebug() == true { | ||
log.Printf("[Gee] %4s - %s", method, pattern) | ||
group.engine.router.addRoute(method, pattern, handler) | ||
} | ||
|
||
group.engine.router.addRoute(method, pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) { | ||
group.addRoute("GET", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) { | ||
group.addRoute("POST", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) PUT(pattern string, handler HandlerFunc) { | ||
group.addRoute("PUT", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) DELETE(pattern string, handler HandlerFunc) { | ||
group.addRoute("DELETE", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) PATCH(pattern string, handler HandlerFunc) { | ||
group.addRoute("PATCH", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) HEAD(pattern string, handler HandlerFunc) { | ||
group.addRoute("HEAD", pattern, handler) | ||
} | ||
|
||
func (group *RouterGroup) OPTIONS(pattern string, handler HandlerFunc) { | ||
group.addRoute("OPTIONS", pattern, handler) | ||
} | ||
|
||
func (engine *Engine) Run(addr string) (err error) { | ||
return http.ListenAndServe(addr, engine) | ||
} | ||
|
||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
var middlewares []HandlerFunc | ||
for _, group := range engine.groups { | ||
if strings.HasPrefix(r.URL.Path, group.prefix) { | ||
middlewares = append(middlewares, group.middlewares...) | ||
} | ||
} | ||
c := NewContext(w, r) | ||
c.handlers = middlewares | ||
engine.router.handle(c) | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package gee | ||
|
||
import ( | ||
"log" | ||
"time" | ||
) | ||
|
||
func Logger() HandlerFunc { | ||
return func(c *Context) { | ||
t := time.Now() | ||
c.Next() | ||
log.Printf("[%d] %s in %v", c.StatusCode, c.Request.RequestURI, time.Since(t)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package gee | ||
|
||
const Logo = ` | ||
*** *** ** ** ** | ||
***** *** *** ** ** | ||
******* *** *** ** ** | ||
*** ** *** *** ** ** | ||
*** *** ** *** ** ** | ||
*** *** ***** ***** ****** ** ***** ******* | ||
** ******* ******* ********* ******* ******** | ||
** ***** *** ** *** ** **** **** *** ** *** *** | ||
** ***** ********* ********* **** *** ********* ** *** | ||
** *** ********* ********* **** *** ********* ** *** | ||
*** *** ** ** **** *** ** ** *** | ||
*** *** *** *** *** *** **** *** *** *** *** ** | ||
******** **** *** **** *** ** *** **** *** **** *** | ||
******** ******* ******* ** *** ******* ******* | ||
*** ** *** *** ** *** *** ** *** | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package gee | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"runtime" | ||
"strings" | ||
) | ||
|
||
func trace(message string) string { | ||
var pcs [32]uintptr | ||
n := runtime.Callers(3, pcs[:]) // skip first 3 caller | ||
|
||
var str strings.Builder | ||
str.WriteString(message + "\nTraceback:") | ||
for _, pc := range pcs[:n] { | ||
fn := runtime.FuncForPC(pc) | ||
file, line := fn.FileLine(pc) | ||
str.WriteString(fmt.Sprintf("\n\t%s:%d", file, line)) | ||
} | ||
return str.String() | ||
} | ||
|
||
func Recovery() HandlerFunc { | ||
return func(c *Context) { | ||
defer func() { | ||
if err := recover(); err != nil { | ||
message := fmt.Sprintf("%s", err) | ||
log.Printf("%s\n\n", trace(message)) | ||
c.Fail(http.StatusInternalServerError, "Internal Server Error") | ||
} | ||
}() | ||
|
||
c.Next() | ||
} | ||
} |
Oops, something went wrong.