Git Product home page Git Product logo

ozzo-routing's People

Contributors

dvrkps avatar filemist avatar jackwhelpton avatar jonathana avatar kolkov avatar metalguardian avatar qiangxue avatar rangelreale avatar samdark avatar westwind-sc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ozzo-routing's Issues

JWT Authorization

Hi,
I wrote middleware for JWT authorization for your framework go-ozzo, ozzo-routing.
If You want i can transfer code of JWT for you without any limits from me
I have plan to write tests for this code and fix comments in code

https://github.com/vvv-v13/ozzo-jwt

Thanks.

Reading array query parameter as `[]time.Time`?

Reading array query parameters doesn't seem to work with common non primitive types (eg. []time.Time, []uuid.UUID, etc.).

Example:

// url: http://localhost:8090/api/test?Names=test1&Dates=2020-10-11T21%3A00%3A00.000Z

data := &struct{
    Names []string
    Dates []time.Time
}{}

ctx.Read(data) // result: { Names: [ "test1" ], Dates: [] }

I guess if an alias type with custom encoding.TextUnmarshaler is provided it would work, but that seems redundant because the non slice version is correctly unmarshalized.

Serving Static Files

Hi!
I think that you need to specify in README that the handler for serving static files must be the latest handler in the routing tree.

`http: multiple response.WriteHeader calls` when using fault.Recovery

test code is:

package main

import (
    "github.com/go-ozzo/ozzo-routing"
    "github.com/go-ozzo/ozzo-routing/fault"
    "log"
    "net/http"
)

func main() {
    router := routing.New()
    router.Use(
        fault.Recovery(log.Printf, func(c *routing.Context, err error) error {
            c.Write(err)
            return nil 
        }), 
    )   
    http.Handle("/", router)
    http.ListenAndServe(":8123", nil)
}

on error occurred, it will log an additional message: http: multiple response.WriteHeader calls

2018/01/24 12:08:54 Not Found
2018/01/24 12:08:54 http: multiple response.WriteHeader calls

Further development of ozzo framework

Qiang, do you plan to develop ozzo like yii in the future? I like yii, but I think that my new project is to big for yii.
I would like to start developing a big project on golang using ozzo right now.)
But I would like to understand the perspectives...

Error in JWT example

Hi! I think this is a error:

 token, err := auth.NewJWT(jwt.StandardClaims{
         Id: id
       }, signingKey)
func NewJWT(claims jwt.MapClaims, signingKey string, signingMethod ...jwt.SigningMethod) (string, error) {
    var sm jwt.SigningMethod = jwt.SigningMethodHS256
    if len(signingMethod) > 0 {
        sm = signingMethod[0]
    }
    return jwt.NewWithClaims(sm, claims).SignedString([]byte(signingKey))
}

HTTPError with StatusBadRequest return a response with 500 Internal Error

Hello,

In the API layer of my app, Every call can return HTTPError with various Status.

For exemple in case of a no found objet for a GET call I return :
return routing.NewHTTPError(http.StatusNotFound, err.Error())
The response head will be correctly set.

But when I use the http.StatusBadRequest in the exact same way (for example a POST with invalid validation):

return routing.NewHTTPError(http.StatusBadRequest)

The response header is set to 500 Internal Server Error instead of 400 Bad request.

Thanks,
Regards,
Arthur

slash.Remover handler works when applied to a router, but not a RouteGroup

In the following code, the slash remover works as expected when I do a GET request against /api/users/

package main

import (
	"net/http"

	"github.com/go-ozzo/ozzo-routing"
	"github.com/go-ozzo/ozzo-routing/slash"
)

func main() {
	router := routing.New()

	router.Use(
		slash.Remover(http.StatusMovedPermanently),
	)

	api := router.Group("/api")
	api.Get("/users", func(c *routing.Context) error {
		return c.Write("user list")
	})

	http.Handle("/", router)
	http.ListenAndServe(":8080", nil)
}
curl -v http://localhost:8080/api/users/
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/users/ HTTP/1.1
> Host: localhost:8080
> User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
> Accept: */*
> Referer: 
> 
< HTTP/1.1 301 Moved Permanently
< Location: /api/users
< Date: Tue, 18 Apr 2017 14:46:41 GMT
< Content-Length: 45
< Content-Type: text/html; charset=utf-8
< 
<a href="/api/users">Moved Permanently</a>.

However, when I put the handler declaration in the route group, by calling api.Use, the slash remover no longer works.

package main

import (
	"net/http"

	"github.com/go-ozzo/ozzo-routing"
	"github.com/go-ozzo/ozzo-routing/slash"
)

func main() {
	router := routing.New()

	api := router.Group("/api")

	api.Use(
		slash.Remover(http.StatusMovedPermanently),
	)

	api.Get("/users", func(c *routing.Context) error {
		return c.Write("user list")
	})

	http.Handle("/", router)
	http.ListenAndServe(":8080", nil)
}
curl -v http://localhost:8080/api/users/
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/users/ HTTP/1.1
> Host: localhost:8080
> User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
> Accept: */*
> Referer: 
> 
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Tue, 18 Apr 2017 14:47:57 GMT
< Content-Length: 10
< 
Not Found

"Routing.context" vs standard library "context" package

It seems that the "Routing.context" is handling a goroutine process, quite similar to the standard library "context" package.

However, the standard library's "context" interface have:

type Context interface {
    Done() <-chan struct{}
    Err() error
    Deadline() (deadline time.Time, ok bool)
    Value(key interface{}) interface{}
}

Is it possible to implement those methods in the "Routing.context"?

I am using other library which uses the standard library "context" as shwon

ctx := context.Background()
posts, resp, err := client.GetPosts.List(ctx, opt)

If the "Routing.context" implements the interface's methods, probably I can just wired the function in a routing handler as such

func getAllPost(c *routing.Context) error {
    posts, resp, err := client.GetPosts.List(c, opt)
    //...
}

Else, may I know what is the best way to create a context within a routing context?

Any reason not to implement the standard "context" method in "routing.context"? I am new to Go, may please advice... ^_^

Serving static files with processed URL

I want to serve images, and those images are saved in a tree-structure directories. The images are saved in the directory based on their first 3 characters of their name.

Example:

If user:

  1. GET /uploads/t4s1h9k0px12.jpg, then serve /uploads/t/4/s/t4s1h9k0px12.jpg
  2. GET /uploads/ya5sx76hgx21_b_adbj65xcgd16.jpg, then serve /uploads/y/a/5/ya5sx76hgx21_b_adbj65xcgd16.jpg

How can I use the file.Server? How to configure the file.PathMap?

router.Get("/*", file.Server(file.PathMap{
	"/": "/ui/",
}))

Do I need to implement a custom routing handler that process the URL, and then just use the standard http library http.ServeContent to serve the corresponding file?

404 error while trying to request /

I receive 404 error while trying to request /

2016/01/02 15:33:17 [127.0.0.1] [0.095ms] GET / HTTP/1.1 404 9

using the example code

r.Get("", func(c *routing.Context) {
    c.Write("Welcome, ozzo!")
})

If I change code to

r.Get("/", func(c *routing.Context) {...})

then request is successful

Tests are running successfully

auth.JWT使用动态密钥

Hi,强哥
在使用auth.JWT过程中,signingKey是根据二级域名动态变化的,那么我要如何使用 r.Use(auth.JWT(signingKey)) ?

Strange error on https with 1503 0100 0202 0a

I start two servers:
http on port 8080
https on port 8088

go func() {
        s := app.C.GetString("WebServer.Domain") + ":" + app.C.GetString("WebServer.PortHTTPS")
        l.Info("Start Serving HTTPS on " + s)
        err := http.ListenAndServeTLS(s, "./ssl/cert.pem", "./ssl/key.pem", nil)
        if err != nil {
            l.Emergency(err.Error())
        }
    }()

    s := app.C.GetString("WebServer.Domain") + ":" + app.C.GetString("WebServer.PortHTTP")
    l.Info("Start Serving HTTP on " + s)
    // Запуск HTTP сервера и редирект всех входящих запросов на HTTPS
    err := http.ListenAndServe(s, http.HandlerFunc(redirectToHttps))
    if err != nil {
        l.Emergency(err.Error())
    }

If i connecting to port 8088 without https begins, Chrome will download a file as follows:

0000000: 1503 0100 0202 0a

What this?

Error in Serving Static Files section

Hi! I try to run code sample:

r := routing.NewRouter()
// serves the files under working-dir/web/assets
r.To("/assets(/.*)?", routing.Static("web"))

But Error is:
not enough arguments in call to routing.Static

if I use:
// serves the files under working-dir/web/assets
st := routing.StaticOptions{"", "", nil}
r.To("(/.*)?", routing.Static("/", st))

everything is working

Thanks!

Routing.Context.Write() not marshaling JSON as expected

I have a struct Person with custom JSON MarshalJSON and UnmarshalJSON methods. When I use the the Write() in a routing handler, it skips these custom methods and use the default JSON marshal/unmarshal.

func GetPerson (c *routing.Context) error {
    // ...
    return c.Write(p) // print JSON with default JSON method, expect custom marshal to be used
}

However, if I wrap the struct in another struct or slice, e.g. :

type User struct {
    UserID  int    `json:"userID"`
    Details Person `json:"details"`
}

Or

[]Person{}

and c.Write(...) these values, the custom marshal methods is used.

E.g.

func GetPerson (c *routing.Context) error {
    u := User{}
    // ... more code
    return c.Write(u) // the custom marshal methods in Person is used (e.g. Birthday in Person have the correct time format)
}

func GetPeople (c *routing.Context) error {
    people := []Person{}
    // ... more code
    return c.Write(people) // the custom marshal methods is being used too (e.g. time format is converted as expected)
}

Is it a bug?* I guess it is something related to http Writter*... Hmmm... may please have a look? :)

Note: the Person struct is included below

type Person struct {
	Name     string    `json:"name"`
	Birthday time.Time `json:"birthday"`
	Hobbies  []Sharing `json:"hobbies"`
}

// MarshalJSON marshal struct.
// - Convert empty slice to "[]" instead of "null"
// - Custom manipulation to certain fields
// - Output time.Time in specific time format used by the app
func (m *Person) MarshalJSON() ([]byte, error) {
	type Alias Person
	if m.Hobbies == nil {
		m.Hobbies = make([]Sharing, 0) //convert to empty array if slice is nil
	}

	return json.Marshal(&struct {
		Name     string `json:"name"`
		Birthday string `json:"birthday"`
		*Alias
	}{
		Name:     "Oh, you need to guess it!",  //custom manipulation
		Birthday: app.TimeToString(m.Birthday), //change time format
		Alias:    (*Alias)(m),
	})
}

// UnmarshalJSON unmarshal JSON to struct data
func (m *Person) UnmarshalJSON(data []byte) error {
	type Alias Person
	aux := &struct {
		Birthday string `json:"birthday"`
		*Alias
	}{
		Alias: (*Alias)(m),
	}
	if err := json.Unmarshal(data, &aux); err != nil {
		return err
	}

	t, err = app.StringToTime(aux.Birthday)
	if err != nil {
		return err
	}
	m.Birthday = t

	return nil
}

How to Organize a project?

In PHP we create root folder and project in it. Such as:

root
-config
-controllers
-models
-views
-utils
-vendor
etc.

My project is an angular.js project.
I need to have one or more index.html file(s) which will load some .js and .css files.
And then Angular.js on frontend will use REST API on backend.

Golang is not a PHP.
Qiang, what is the best way to organaize a project in the root folder?
What do you think about this?
Thanks!

Can we use this feature to populate all nested struct fields?

Hi! I try to find the way to populate DDD aggregate with simple joined query. At this moment it possible only by giving all needed fields in select query. I whant to use this way to populate all struct with nested struct fields at once.
https://stackoverflow.com/a/13153422

For example:

type Wagon struct {
    Wagon
    State WagonState
    Location WagonLocation
}

with

...
Select(
    "w.*",
    "ws.*",
    "wl.*"
).From("wagon w").
InnerJoin("wagon_state ws", dbx.NewExp("ws.id=w.state_id")).
InnerJoin("wagon_location wl", dbx.NewExp("wl.id=w.location_id")).
...

Is it possible to add to this lib?

Error handling is not conform with OpenAPI standard

the router sets for each error case a content type "text/plain" but that behavior is to static. Could you introduce a customizable error handler that the user can decide self what kind of content he wants sending to the cunsomer back or you could extending the collection of http errors (JSON, XML, Text, etc) and error matching.

bildschirmfoto 2018-07-10 um 09 53 54

Behavior of content type
Type
https://tools.ietf.org/search/rfc2616#section-7.2
Entity body
https://tools.ietf.org/search/rfc2616#section-7.2.1

lost closing bracket in example

func main() {
//     r := routing.New()
//     r.Use(auth.Basic(func(c *routing.Context, username, password string) (auth.Identity, error) {
//       if username == "demo" && password == "foo" {
//         return auth.Identity(username), nil
//       }
//       return nil, errors.New("invalid credential")
//     }))
//     r.Get("/demo", func(c *routing.Context) error {
//       fmt.Fprintf(res, "Hello, %v", c.Get(auth.User))
//       return nil
//     })
//   }

})) - lost closing bracket in example

Add support for fasthttp

It would be great adding support for fasthttp in ozzo-routing. Fasthttp is extremely fast and it doesn't allocate memory in fast paths. So fasthttp-backed ozzo-routing will allow writing low-overhead http servers with advanced routing capabilities.

Serving Static Html file for not found endpoints.

I was going through the documentation and I saw the explanation given about error handling.

What I am trying to achieve is being able to return an html file in a situation where the endpoint is not provided. I wanted to just go ahead and add my function for 404/not found errors.

But, I was concerned about it interfering with situations where I return a 404 itself. E.g: When a user makes a request to get information about a user and the user isn't available.

Your response and suggestion would be greatly appreciated.

Thanks

关于部分函数的用法

强哥,当我调用Use()后
router.Use(
// all these handlers are shared by every route
access.Logger(log.Printf),
slash.Remover(http.StatusMovedPermanently),
fault.Recovery(log.Printf),
)
之后的操作我没太明白,access.Logger(log.Printf),slash.Remover(http.StatusMovedPermanently),fault.Recovery(log.Printf),在以后的程序中是如何使用的呢?

关于优雅重启的问题?

Hi,强哥:
一直想问您,有没有写关于server优雅重启的组件。热更新配置,http请求超时处理这些功能的组件。

Benchmarks please

the performance is comparative to that of httprouter and gin

Do you have benchmarks that show this?

NewContext() is not populating parameters from provided URL

I'm trying to write a unit test, as I would in Express+Supertest. I'm finding that when I provide a test URL, that the parameters are not parsed.

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/go-ozzo/ozzo-routing"
	"github.com/go-ozzo/ozzo-routing/content"
	"github.com/stretchr/testify/assert"
)

func TestContextParamsPopulatedByOzzo(test *testing.T) {
	assert := assert.New(test)

	// Initialize app
	router := routing.New()
	router.Get("/test/<id>", routing.NotFoundHandler)

	// Mock up a request
	res := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/test/23", nil)
	assert.NoError(err)

	// Mock up a routing context
	routeCtx := routing.NewContext(res, req)

	// Sanity check
	assert.Equal("23", routeCtx.Param("id"))
}

Bypass handler

Hi!
Is a way to bypass handler in server func? I try to find way to bypass auth handler for public routes.
Or the best way to have diferent routes for private and public?

Common ozzo repo.

Hi!
I think we need to create a common repository for discussion on common framework questions and future requests.

Router Use() how to use

hi~,I do not know how to use the Use() after seeing the example ,how can i use?Could you give a example ?
thanks

Unable to get POST data from app/json request

Hi! I Got issue when there is no way to get data with content-type app/json (while urlencoded form works fine)
I tried both of methods (in source code they looks similar):

email := c.PostForm("email")
email := c.Form("email")

Also tried context.Read() like it was shown in README but with no result - also empty response.
Here is the example of my request:

POST http://localhost:8080/api/user/username/create HTTP/1.1
Accept: application/json
Content-Type: application/json
{
  "about": "About me.",
  "email": "[email protected]",
  "fullname": "John Smith"
}

All of theese fields are empty in c *routing.Context. Can you help me and show me what I'm doing wrong? Thanks in advice!

How better set response encoding?

Hi!
I am using content.TypeNegotiator(content.JSON)
But for some reason there is no encoding set (charset=UTF-8).
How do I better set the response encoding for the all application at once?
Thank you!

Add function to delete internal context.data

We use c.Set("isUser", true) to pass data to other handlers, sometimes in complex functions, we may use a few handlers inside a handler, some handlers may required some internal data to be set while other handlers do not need those data, so hope to have a function to "delete" the context.data

func abc123(c *routing.Context) error {

    c.Set("name1", true)
    err := cde123(c)

    c.Delete("name1") // <-- hope to have something like that to delete internal data
    err := cde123(c)

    return nil
}

Enable "reverse-engineering" a URI to determine the corresponding route and parameters

I would like to be able to take a URI from the body of an HTTP request, something like:

/products/1234

and programmatically determine that this matches to a route:

/products/{id}

with "id" = 1234. This is obviously something the ozzo-routing framework is doing internally, and from a cursory inspection it looks like it could probably be accomplished by exposing the "store" object publicly.

Does this make sense? I'm happy to have a look at how it could be done in a separate fork... would a PR be considered if I can get it to work?

Missing current route

I am missing the abillity to find out which route actually matched.

The use case for this would be for example rendering a menu and highlighting the item matching the current route.

What is meaning of ozzo? Could your provide its road map? Thanks.

Dear Qian,

I use Yii1/2 for create some web solutions:) Thanks for your fantastic framework.

We know the trend will be more JS frontend + RESTful backend, so that may be your reason to start pay time to golang, and create new web framework.

Could you advise what is the meaning of ozzo?
In one of your article, you compare many routing fw, do the ozzo will be beat them:)
And what is your philosophy and road map for this ozzo web framework?

I would like to be act as early adopter:) Thanks.

Regards,
Scott Huang

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.