Skip to content

Commit

Permalink
feat: query params, path params, cookies and headers getters and setters
Browse files Browse the repository at this point in the history
  • Loading branch information
hokamsingh committed Aug 21, 2024
1 parent 8d52a57 commit 3141d20
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 14 deletions.
106 changes: 104 additions & 2 deletions internal/core/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"

"github.com/gorilla/mux"
)

// Context holds the request and response writer and provides utility methods.
type Context struct {
Req *http.Request
Res http.ResponseWriter
Req *http.Request
Res http.ResponseWriter
responseSent bool // Track whether a response has been sent
}

// NewContext creates a new Context instance.
Expand Down Expand Up @@ -45,9 +50,38 @@ func (c *Context) GetJSONBody() (map[string]interface{}, bool) {
//
// ctx.JSON(http.StatusOK, map[string]string{"message": "success"})
func (c *Context) JSON(status int, v interface{}) {
if c.responseSent {
log.Fatal("Response already sent")
return
}
c.Res.Header().Set("Content-Type", "application/json")
c.Res.WriteHeader(status)
json.NewEncoder(c.Res).Encode(v)
c.responseSent = true
c.Res.(http.Flusher).Flush() // Ensures the data is sent to the client
}

// Send sends a plain text response.
//
// This method sets the Content-Type to text/plain and writes the provided value as a response.
//
// Parameters:
//
// v (any): The value to send in the response. It will be converted to a string.
//
// Example usage:
//
// ctx.Send("Hello, World!")
func (c *Context) Send(v any) {
if c.responseSent {
log.Fatal("Response already sent")
return
}
c.SetHeader("Content-Type", "text/plain")
c.Res.WriteHeader(http.StatusOK)
c.Res.Write([]byte(fmt.Sprint(v)))
c.responseSent = true
c.Res.(http.Flusher).Flush() // Ensures the data is sent to the client
}

// Error sends an error response with the given status code and message.
Expand All @@ -63,9 +97,16 @@ func (c *Context) JSON(status int, v interface{}) {
//
// ctx.Error(http.StatusBadRequest, "Invalid request")
func (c *Context) Error(status int, message string) {
if c.responseSent {
log.Fatal("Response already sent")
return
}
c.Res.Header().Set("Content-Type", "application/json")
c.Res.WriteHeader(status)
json.NewEncoder(c.Res).Encode(map[string]string{"error": message})
// Close the response after sending the error
c.responseSent = true
c.Res.(http.Flusher).Flush() // Ensures the data is sent to the client
}

// Body parses the JSON request body into the provided interface.
Expand Down Expand Up @@ -113,6 +154,10 @@ func (c *Context) Body(v interface{}) error {
//
// ctx.Redirect(http.StatusSeeOther, "/new-url")
func (c *Context) Redirect(status int, url string) {
if c.responseSent {
log.Fatal("Response already sent")
return
}
http.Redirect(c.Res, c.Req, url, status)
}

Expand Down Expand Up @@ -162,3 +207,60 @@ func (c *Context) GetCookie(name string) (string, bool) {
}
return cookie.Value, true
}

// GetParam retrieves a URL parameter from the request.
// Assumes that parameters are stored in the request context.
func (c *Context) GetParam(name string) (string, bool) {
params, ok := c.GetAllParams()
if !ok {
return "", false
}
value, found := params[name]
return value, found
}

// GetAllParams retrieves all URL parameters from the request.
//
// This method returns a map containing all URL parameters with their respective values
// and a boolean indicating whether any parameters were found.
//
// Returns:
//
// (map[string]string, bool): A map of URL parameters and a boolean indicating if any were found.
func (c *Context) GetAllParams() (map[string]string, bool) {
params := mux.Vars(c.Req)
if len(params) == 0 {
return nil, false
}
return params, true
}

// GetQuery retrieves a query parameter from the request URL.
func (c *Context) GetQuery(name string) (string, bool) {
values := c.Req.URL.Query()
value := values.Get(name)
return value, value != ""
}

// GetAllQuery retrieves all query parameters as a JSON object.
func (c *Context) GetAllQuery() (map[string]interface{}, error) {
queryMap := make(map[string]interface{})
for key, values := range c.Req.URL.Query() {
if len(values) > 1 {
queryMap[key] = values
} else {
queryMap[key] = values[0]
}
}
return queryMap, nil
}

// GetHeader retrieves a header value from the request.
func (c *Context) GetHeader(name string) string {
return c.Req.Header.Get(name)
}

// SetHeader sets a header value for the response.
func (c *Context) SetHeader(name, value string) {
c.Res.Header().Set(name, value)
}
17 changes: 10 additions & 7 deletions internal/core/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Router struct {
type Option func(*Router)

// Default CORS options
var defaultCORSOptions = middleware.CORSOptions{
var _ = middleware.CORSOptions{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
Expand Down Expand Up @@ -310,15 +310,18 @@ func (r *Router) withContext(next CustomHandler, method string) http.HandlerFunc
//
// Example usage:
//
// http.Handle("/static/", ServeStatic("/static/", "/path/to/static/files"))
func ServeStatic(pathPrefix, dir string) http.Handler {
// Resolve the absolute path for debugging
// r := LessGo.NewRouter(
// LessGo.WithCORS(*corsOptions),
// LessGo.WithRateLimiter(100, 1*time.Minute),
// LessGo.WithJSONParser(),
// LessGo.WithCookieParser(),
// )
// r.ServeStatic("/static/", "/path/to/static/files"))
func (r *Router) ServeStatic(pathPrefix, dir string) {
absPath, err := filepath.Abs(dir)
if err != nil {
log.Fatalf("Failed to resolve absolute path: %v", err)
}
log.Printf("Serving static files from: %s", absPath)

fs := http.FileServer(http.Dir(absPath))
return http.StripPrefix(pathPrefix, fs)
r.Mux.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix, fs))
}
9 changes: 4 additions & 5 deletions pkg/lessgo/less.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package LessGo

import (
"net/http"
"time"

"github.com/hokamsingh/lessgo/internal/core/config"
Expand Down Expand Up @@ -80,10 +79,10 @@ func WithFileUpload(uploadDir string) router.Option {
return router.WithFileUpload(uploadDir)
}

// ServeStatic creates a file server handler to serve static files
func ServeStatic(pathPrefix, dir string) http.Handler {
return router.ServeStatic(pathPrefix, dir)
}
// // ServeStatic creates a file server handler to serve static files
// func ServeStatic(pathPrefix, dir string) http.Handler {
// return router.ServeStatic(pathPrefix, dir)
// }

func GetFolderPath(folderName string) (string, error) {
return utils.GetFolderPath(folderName)
Expand Down

0 comments on commit 3141d20

Please sign in to comment.