diff --git a/api.go b/api.go new file mode 100644 index 0000000..e43c6f1 --- /dev/null +++ b/api.go @@ -0,0 +1,99 @@ +package bond + +import ( + //"io" + "encoding/json" + "net/http" + "net/url" + "fmt" +) + +type ContentType string + +const ( + PlainText ContentType = "text/plain; charset=utf-8" +) + +type Decoder interface { + Decode(any) error +} + +type ApiFunc func(*Context) +func (fn ApiFunc) ServeHTTP(w ResponseWriter, r *Request) { + fn(&Context{ + R: r, + W: w, + }) +} + +type Context struct { + R *Request + W ResponseWriter + // Custom data to store stuff. + Data any + dec Decoder +} + +func (c *Context) SetContentType(typ ContentType) { + c.SetHeader("Content-Type", string(typ)) +} + +func (c *Context) ContentType() string { + ret, ok := c.Header("Content-Type") + if !ok { + return "" + } + if len(ret) < 1 { + return "" + } + return ret[0] +} + +func (c *Context) SetHeader(k, v string) { + c.W.Header().Set(k, v) +} + +func (c *Context) Header(name string) ([]string, bool) { + ret, ok := c.R.Header[name] + return ret, ok +} + +// Closes the requests body after finishes scaning. +func (c *Context) Close() { + c.R.Body.Close() +} + +// Scan the incoming value from body depending +// on the content type of the request. +func (c *Context) Scan(v any) error { + if c.dec == nil { + typ := c.ContentType() + switch typ { + case "application/json" : + c.dec = json.NewDecoder(c.R.Body) + default: + return UnknownContentTypeErr + } + } + err := c.dec.Decode(v) + if err != nil { + return err + } + return nil +} + +func (c *Context) Path() string { + return c.R.URL.Path +} + +func (c *Context) NotFound() { + http.NotFound(c.W, c.R) +} + +func (c *Context) Printf(format string, v ...any) (int, error) { + return fmt.Fprintf(c.W, format, v...) +} + +func (c *Context) Query() url.Values { + return c.R.URL.Query() +} diff --git a/cmd/test/main.go b/cmd/test/main.go index b8932b7..f37841d 100644 --- a/cmd/test/main.go +++ b/cmd/test/main.go @@ -7,25 +7,42 @@ import ( var root = bond.Mux(). Def( "", - bond.ContextFunc(func(c *bond.Context){ + bond.ApiFunc(func(c *bond.Context){ c.W.Write([]byte("This is the index page")) }), ).Def( "hello", bond.Mux().Def( "en", - bond.ContextFunc(func(c *bond.Context){ + bond.ApiFunc(func(c *bond.Context){ c.W.Write([]byte("Hello, World!")) }), ).Def( "ru", - bond.ContextFunc(func(c *bond.Context){ + bond.ApiFunc(func(c *bond.Context){ c.W.Write([]byte("Привет, Мир!")) }), ), ).Def( "web", bond.Static("./static"), +).Def( + "test", + bond.ApiFunc(func(c *bond.Context){ + c.SetContentType(bond.PlainText) + c.Printf( + "Path: %q\n" + + "Content-Type: %q\n", + c.Path(), c.ContentType(), + ) + c.Printf("Query:\n") + for k, vs := range c.Query() { + c.Printf("\t%q:\n", k) + for _, v := range vs { + c.Printf("\t\t%q\n", v) + } + } + }), ) func main() { diff --git a/errors.go b/errors.go index e78a765..867506d 100644 --- a/errors.go +++ b/errors.go @@ -6,4 +6,5 @@ import ( var ( DupDefErr = errors.New("duplicate route define") + UnknownContentTypeErr = errors.New("unknown content type") ) diff --git a/handler.go b/handler.go index e124cbf..d94829f 100644 --- a/handler.go +++ b/handler.go @@ -10,19 +10,6 @@ type HandlerFunc = http.HandlerFunc type Handler = http.Handler type Server = http.Server -type Context struct { - R *Request - W ResponseWriter -} - -type ContextFunc func(*Context) -func (fn ContextFunc) ServeHTTP(w ResponseWriter, r *Request) { - fn(&Context{ - R: r, - W: w, - }) -} - func Static(pth string) Handler { return http.FileServer(http.Dir(pth)) }