Skip to content

Commit

Permalink
Merge pull request #22 from ferry-go/feature/core/added-utilities
Browse files Browse the repository at this point in the history
Feature/core/added utilities
  • Loading branch information
pittalamadhuri authored Jul 16, 2020
2 parents 497a549 + 12be996 commit 14277cd
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 103 deletions.
13 changes: 7 additions & 6 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package ferry

import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
Expand All @@ -22,7 +21,7 @@ type Ctx struct {

// Json Sending application/json response
func (ctx *Ctx) Json(statusCode int, payload interface{}) error {
ctx.RequestCtx.Response.Header.Set("Content-Type", "application/json")
ctx.RequestCtx.Response.Header.Set(ContentType, ApplicationJson)
ctx.RequestCtx.SetStatusCode(statusCode)
response, err := json.Marshal(payload)
if err != nil {
Expand All @@ -48,6 +47,8 @@ func (ctx *Ctx) Redirect(statusCode int, url string) error {
}

// SendAttachment Sending attachment
//
// here fileName is optional
func (ctx *Ctx) SendAttachment(filePath, fileName string) error {
f, err := os.Open(filePath)
if err != nil {
Expand All @@ -61,9 +62,9 @@ func (ctx *Ctx) SendAttachment(filePath, fileName string) error {
if err != nil {
panic(err)
}
ctx.RequestCtx.Response.Header.Set("Content-Type", contentType)
headerValue := fmt.Sprintf("attachment; filename=%s", fileName)
ctx.RequestCtx.Response.Header.Set("Content-Disposition", headerValue)
ctx.RequestCtx.Response.Header.Set(ContentType, contentType)
headerValue := getAttachmentHeader(fileName)
ctx.RequestCtx.Response.Header.Set(ContentDeposition, headerValue)
ctx.RequestCtx.SetBody(content)
return nil
}
Expand Down Expand Up @@ -159,7 +160,7 @@ func (ctx *Ctx) ServeFile(filePath string) error {
if err != nil {
return err
}
ctx.RequestCtx.Response.Header.Set("Content-Type", contentType)
ctx.RequestCtx.Response.Header.Set(ContentType, contentType)
return ctx.RequestCtx.Response.SendFile(filePath)
}

Expand Down
97 changes: 1 addition & 96 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"net/http"
"regexp"
"strings"
)

// Middleware/Route Handler
Expand All @@ -26,15 +25,6 @@ type group struct {
middlewareCurrentIndex int
}

var (
GET = http.MethodGet
POST = http.MethodPost
PUT = http.MethodPut
DELETE = http.MethodDelete
)

var routerRegexReplace = "[a-zA-Z0-9_-]*"

func (g *group) addRoute(method, path string, h ...handler) {
groupPath := fmt.Sprintf("%s%s", g.path, path)
pathWithRegex := findAndReplace(groupPath)
Expand Down Expand Up @@ -87,7 +77,7 @@ func handle404(ferry *Ferry, ctx *Ctx) {
return
}
ctx.RequestCtx.Response.SetStatusCode(http.StatusNotFound)
ctx.RequestCtx.Response.SetBody([]byte("Not Found, Check URL"))
ctx.RequestCtx.Response.SetBody([]byte(NotFoundMessage))
}

func handlerRouterError(err error, ctx *Ctx, ferry *Ferry) {
Expand All @@ -114,31 +104,6 @@ func handleRouting(ferry *Ferry, ctx *Ctx) {

}

// Finds wild card in URL and replace them with a regex for,
// ex if path is /auth/:name -> /auth/[a-zA-Z0-9]*
// ex if path is /auth/name -> /auth/name
func findAndReplace(path string) string {
if !strings.Contains(path, ":") {
return fmt.Sprintf("%s%s%s", "^", path, "$")
}
result := ""
slitted := strings.Split(path, "/")
for _, v := range slitted {
if v == "" {
continue
}
if strings.Contains(v, ":") {
result = fmt.Sprintf("%s/%s", result, routerRegexReplace)
continue
}
result = fmt.Sprintf("%s/%s", result, v)
}
// replace slashes
result = strings.ReplaceAll(result, "/", "\\/")
result = fmt.Sprintf("%s%s%s", "^", result, "$")
return result
}

// calls actual handler
func handleRouter(ctx *Ctx, ferry *Ferry, routers []router) {
urlPath := string(ctx.RequestCtx.Path())
Expand Down Expand Up @@ -173,63 +138,3 @@ func handleRouter(ctx *Ctx, ferry *Ferry, routers []router) {
handle404(ferry, ctx)
}
}

// routerPath /auth/:name
// requestPath /auth/madhuri
// paramName name
// returns madhuri
func extractParamFromPath(routerPath, requestPath, paramName string) string {
routerSplit := strings.Split(routerPath, "/")
requestSplit := strings.Split(requestPath, "/")
if len(routerSplit) != len(requestSplit) {
return ""
}
paramWithWildCard := fmt.Sprintf(":%s", paramName)
for k, v := range routerSplit {
if v == paramWithWildCard {
return requestSplit[k]
}
}
return ""
}

// routerPath /auth/:name/:age
// requestPath /auth/madhuri/32
// returns { name: madhuri, age: 32 }
func getParamsFromPath(routerPath, requestPath string) map[string]string {
paramsMap := map[string]string{}
routerSplit := strings.Split(routerPath, "/")
requestSplit := strings.Split(requestPath, "/")
for k, v := range routerSplit {
if strings.Contains(v, ":") {
key := strings.ReplaceAll(v, ":", "")
paramsMap[key] = requestSplit[k]
}
}
return paramsMap
}

func getAllQueryParams(querypath string) map[string]string {
queryParamsMap := map[string]string{}
params := strings.Split(querypath, "&")
for _, v := range params {
if strings.Contains(v, "=") {
pair := strings.Split(v, "=")
queryParamsMap[pair[0]] = pair[1]
}
}
return queryParamsMap
}

func getQueryParam(querypath string, name string) string {
params := strings.Split(querypath, "&")
for _, v := range params {
if strings.Contains(v, "=") {
pair := strings.Split(v, "=")
if pair[0] == name {
return pair[1]
}
}
}
return ""
}
2 changes: 1 addition & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (ferry *Ferry) HandleErrors(h errHandler) {
// Serving
func (ferry *Ferry) serveFile(path, filePath, contentType string) {
ferry.Get(path, func(ctx *Ctx) error {
ctx.RequestCtx.Response.Header.Set("Content-Type", contentType)
ctx.RequestCtx.Response.Header.Set(ContentType, contentType)
return ctx.RequestCtx.Response.SendFile(filePath)
})
}
Expand Down
129 changes: 129 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package ferry

import (
"fmt"
"net/http"
"strings"
)

const (
GET = http.MethodGet
POST = http.MethodPost
PUT = http.MethodPut
DELETE = http.MethodDelete

// headers
ContentType = "Content-Type"
ContentDeposition = "Content-Disposition"
ApplicationJson = "application/json"
Attachment = "attachment"

routerRegexReplace = "[a-zA-Z0-9_-]*"

// routing error messages
NotFoundMessage = "Not Found, Check URL"
)

// Finds wild card in URL and replace them with a regex for,
// ex if path is /auth/:name -> /auth/[a-zA-Z0-9]*
// ex if path is /auth/name -> /auth/name
func findAndReplace(path string) string {
if !strings.Contains(path, ":") {
return fmt.Sprintf("%s%s%s", "^", path, "$")
}
result := ""
slitted := strings.Split(path, "/")
for _, v := range slitted {
if v == "" {
continue
}
if strings.Contains(v, ":") {
result = fmt.Sprintf("%s/%s", result, routerRegexReplace)
continue
}
result = fmt.Sprintf("%s/%s", result, v)
}
// replace slashes
result = strings.ReplaceAll(result, "/", "\\/")
result = fmt.Sprintf("%s%s%s", "^", result, "$")
return result
}

// routerPath /auth/:name
// requestPath /auth/madhuri
// paramName name
// returns madhuri
func extractParamFromPath(routerPath, requestPath, paramName string) string {
routerSplit := strings.Split(routerPath, "/")
requestSplit := strings.Split(requestPath, "/")
if len(routerSplit) != len(requestSplit) {
return ""
}
paramWithWildCard := fmt.Sprintf(":%s", paramName)
for k, v := range routerSplit {
if v == paramWithWildCard {
return requestSplit[k]
}
}
return ""
}

// routerPath /auth/:name/:age
// requestPath /auth/madhuri/32
// returns { name: madhuri, age: 32 }
func getParamsFromPath(routerPath, requestPath string) map[string]string {
paramsMap := map[string]string{}
routerSplit := strings.Split(routerPath, "/")
requestSplit := strings.Split(requestPath, "/")
for k, v := range routerSplit {
if strings.Contains(v, ":") {
key := strings.ReplaceAll(v, ":", "")
paramsMap[key] = requestSplit[k]
}
}
return paramsMap
}

// returns value of a single query Param
//
// route path /hello?key=test&value=bbp
//
// keyValue = GetQueryParam(key)
//
// keyValue = test
func getAllQueryParams(queryPath string) map[string]string {
queryParamsMap := map[string]string{}
params := strings.Split(queryPath, "&")
for _, v := range params {
if strings.Contains(v, "=") {
pair := strings.Split(v, "=")
queryParamsMap[pair[0]] = pair[1]
}
}
return queryParamsMap
}

// returns map of query Params
//
// route path /hello?key=test&value=bbp
//
// returns {key : test, value : bbp}
func getQueryParam(querypath string, name string) string {
params := strings.Split(querypath, "&")
for _, v := range params {
if strings.Contains(v, "=") {
pair := strings.Split(v, "=")
if pair[0] == name {
return pair[1]
}
}
}
return ""
}

func getAttachmentHeader(fileName string) string {
if fileName == "" {
return fmt.Sprintf(Attachment)
}
return fmt.Sprintf("%s; filename=%s", Attachment, fileName)
}
65 changes: 65 additions & 0 deletions utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ferry

import (
"fmt"
"github.com/go-playground/assert/v2"
"regexp"
"testing"
)

func TestAttachmentHeader(t *testing.T) {
fileName := "hey"
attachment := getAttachmentHeader(fileName)
attachmentExpected := fmt.Sprintf("%s; filename=%s", Attachment, fileName)
assert.Equal(t, attachment, attachmentExpected)
}

func TestPathParamRegex(t *testing.T) {
pathParam := "/auth/:name"
routerParam := "/auth/ferry"
regexParam := findAndReplace(pathParam)
assert.MatchRegex(t, routerParam, regexParam)
}

func TestPathParamRegexAbs(t *testing.T) {
pathParam := "/auth/ferry"
routerParam := "/auth/ferry"
regexParam := findAndReplace(pathParam)
assert.MatchRegex(t, routerParam, regexParam)
}

func TestPathParamRegexFail(t *testing.T) {
pathParam := "/auth/:name"
routerParam := "/auth/ferry/ss"
regexParam := findAndReplace(pathParam)
fail, _ := regexp.MatchString(routerParam, regexParam)
assert.Equal(t, false, fail)
}

func TestGetParam(t *testing.T) {
name := "ferry"
pathParam := "/auth/:name/hello/:age"
routerParam := fmt.Sprintf("/auth/%s/hello/%d", name, 1)
wantedName := extractParamFromPath(pathParam, routerParam, "name")
assert.Equal(t, wantedName, name)
}

func TestGetParamEmpty(t *testing.T) {
name := ""
pathParam := "/auth/:name"
routerParam := "/auth/" + name
wantedName := extractParamFromPath(pathParam, routerParam, "names")
assert.Equal(t, wantedName, name)
}

func TestGetParams(t *testing.T) {
name := "ferry"
pathParam := "/auth/:name/hello/:age"
routerParam := fmt.Sprintf("/auth/%s/hello/%d", name, 1)
paramsMap := getParamsFromPath(pathParam, routerParam)
wantedParamsMap := map[string]string{
"name": name,
"age": "1",
}
assert.Equal(t, paramsMap, wantedParamsMap)
}

0 comments on commit 14277cd

Please sign in to comment.