ant0ine / go-json-rest Goto Github PK
View Code? Open in Web Editor NEWA quick and easy way to setup a RESTful JSON API
Home Page: https://ant0ine.github.io/go-json-rest/
License: MIT License
A quick and easy way to setup a RESTful JSON API
Home Page: https://ant0ine.github.io/go-json-rest/
License: MIT License
standard helpers from the net/http package are usable:
http.Error(w, err.Error(), 500)
http.NotFound(w, r.Request)
But helpers specialized for JSON REST could be better.
something that returns:
{"error":"resource not found"}
instead of:
Page not found
The path params should allow a "."
Currently this site would break john.doe into two path params, and I think it should just be one: something.com/users/john.doe/updates
Right now the endpoint function signatures look like that:
func Get(w *rest.ResponseWriter, r *rest.Request)
what if I want to map to an object method ?
the current solution is:
handler.SetRoutes(
rest.Route{
"GET",
"/countries/:code",
func(w *rest.ResponseWriter, r *rest.Request) {
country_handler.Get(w *rest.ResponseWriter, r *rest.Request)
}
}
)
It could be easier !
Hi, how about using logger interface in resource handler? I'm using https://github.com/Sirupsen/logrus in my application and want specify that logger to go-json-rest. There is example of such interface here: https://godoc.org/github.com/Sirupsen/logrus#StdLogger.
I am using go-json-rest for current project Rest Implementation. I saw that unicode(utf-8) text in JSON is not rendering correctly correctly in browser(Chrome) I think we need send correct content type with charset like
self.Header().Set("Content-Type", "application/json; charset=utf-8")
in https://github.com/ant0ine/go-json-rest/blob/master/response.go#L18
It'd be nice if there was a way to access the http.Response through the ResponseWriter or otherwise a way to set the http StatusCode for the response.
Currently, rest.ResponseWriter is a struct, which breaks the Go convention, I think.
It should be an interface OR it can be renamed rest.Response (implementing the http.ResponseWriter interface)
Heyo! I'm sort of a go newbie, so hopefully this isn't a stupid question -- but how could I go about changing the rest.Error(...) JSON payload?
Right now, if I use rest.Error it returns a JSON dict that looks like this:
{"Error": "..."}
I'd like to make the "Error" string lowercase ("error") to be more consistent with the rest of my API.
Thanks!
What is the common practice in Go to write net/http tests ?
When an object is POSTed to be added some advocate returning a "201 Created" response. It is currently not possible to do so with go-json-rest as Error only returns a string (and we are not returning a real error) and WriteJson doesn't allow to set a response code and will always return 200 for us. It is also not possible to set the error before calling WriteJson since then the headers are sent and the attempt to set the header in WriteJson will fail.
Hi, any examples on how to post json with binary files ?
Currently the output with indentation doesn't include a final newline, this means that when I get the response with curl the command line starts after the response and is slightly messed up.
It is trivial to handle it at the command line by adding an echo command after curl but the point of indentation is to make things completely readable and easy on the api user. Hence it would be nice to add the newline. It might be nice to do it for the non-indented output too.
Can there be an option to not default a response writer's Content-Type header? In your code, you force call WriteHeader on Write with your implementation of WriteHeader always adding an "application/json" Content-Type: https://github.com/ant0ine/go-json-rest/blob/master/rest/response.go#L61.
I realize the package is meant for json only, but there are some instances where it'd be nice to be able to define a certain route or subroutes as non-JSON. For example, it'd be nice to do:
func handlepprof(w rest.ResponseWriter, r *rest.Request) {
switch {
case strings.HasPrefix(r.URL.Path, "/debug/pprof/cmdline"):
pprof.Cmdline(w.(http.ResponseWriter), r.Request)
case strings.HasPrefix(r.URL.Path, "/debug/pprof/profile"):
pprof.Profile(w.(http.ResponseWriter), r.Request)
case strings.HasPrefix(r.URL.Path, "/debug/pprof/symbol"):
pprof.Symbol(w.(http.ResponseWriter), r.Request)
default: // debug/pprof base
pprof.Index(w.(http.ResponseWriter), r.Request)
}
}
with a route {"GET", "/debug/*", handlepprof},
and view the net/http/pprof output in elinks. This could be done with another option in the ResourceHandler
type, such as EnableRelaxedResponseType
similar to the current EnableRelaxedContentType
. Then your WriteHeader could simply not write the Content-Type if this option is set.
What do you think?
Is there a way to define arguments in path? For example:
GIven the url : http://lcoalhost/user?name=John
rest.RouteObjectMethod("GET", "/user", &user, "Find")
func (u *User) Find(w *rest.ResponseWriter, req *rest.Request) {
name := req.PathParam("name") // name = John
...
}
a path like
"/page/:id"
and a url like
/page/bmw-330?p=1
results in a r.PathParam("id") == "bmw-330?p=1"
Shouldn't the routes be based purely on the paths, so the id would be "bmw-330"
If so then the fix is easy
In router.go
if line 95 was changed from ...
urlObj.RequestURI()
to
urlObj.Path
I can't make the library works with standart websocket package.
Hello, Antoine.
I have a problem about url route match.
First handler.SetRoutes
// route matching have problem, don't work.
handler.SetRoutes(
rest.Route{"GET", "/book/:id", GetBookFromBookId},
rest.Route{"GET", "/book/isbn/:isbn", GetBookFromBookISBN},
rest.Route{"GET", "/book/search", GetBookListFromKeyword},
)
Second handler.SetRoutes
// route matching have no problem, work fine
handler.SetRoutes(
rest.Route{"GET", "/book/search", GetBookListFromKeyword},
rest.Route{"GET", "/book/:id", GetBookFromBookId},
rest.Route{"GET", "/book/isbn/:isbn", GetBookFromBookISBN},
)
First handler.SetRoutes has a problem is
GET /book/10112011
GetBookFromBookId handle it.
GET /book/search?q=Java
GetBookFromBookId handle it, so the rest server return not found error.
Second handler.SetRoutes work fine.
GET /book/10112011
GetBookFromBookId handle it.
GET /book/search?q=Java
GetBookListFromKeyword handle it.
Would be nice to see an example turning on Gzip, as it is suggested to be enabled in production in the docs.
...to allow for backward incompatible changes in the future.
If I understand correctly, you abandoned the go-urlrouter package and its code continues to evolve here.
While this package is great for its use case, I think, it is unfortunate, that now the router is unusable by itself for people who use their own resource handlers.
Thus, could you make the router available again by exporting its values and methods just like in go-urlrouter.
Thanks. Great work.
https://github.com/ant0ine/go-json-rest#gorm
handler.SetRoutes(
&rest.RouteObjectMethod("GET", "/reminders", &api, "GetAllReminders"),
&rest.RouteObjectMethod("POST", "/reminders", &api, "PostReminder"),
&rest.RouteObjectMethod("GET", "/reminders/:id", &api, "GetReminder"),
&rest.RouteObjectMethod("PUT", "/reminders/:id", &api, "PutReminder"),
&rest.RouteObjectMethod("DELETE", "/reminders/:id", &api, "DeleteReminder"),
)
This does not compile:
./main.go:22: cannot take the address of rest.RouteObjectMethod("GET", "/reminders", &api, "GetAllReminders")
./main.go:22: cannot use &rest.RouteObjectMethod("GET", "/reminders", &api, "GetAllReminders") (type **rest.Route) as type *rest.Route in argument to handler.SetRoutes
Removing &
solves it.
This project is called go-json-rest.
Is there some design decision made to supprt only json? I mean, changing encoding to xml is as easy as importing encoding/xml.
What is the attitude about including also xml encoding?
I made a mistake:
rest.RouteObjectMethod("GET", "admin/products.json", &api, "GetAllProducts")
Which caused a cryptic panic message:
2014/07/04 09:45:14 http: panic serving 127.0.0.1:43177: runtime error: invalid memory address or nil pointer dereference
goroutine 39 [running]:
net/http.func·011()
/usr/local/go/src/pkg/net/http/server.go:1100 +0xb7
runtime.panic(0x732e20, 0x943f53)
/usr/local/go/src/pkg/runtime/panic.c:248 +0x18d
github.com/ant0ine/go-json-rest/rest.(*ResourceHandler).ServeHTTP(0xc208005320, 0x7f4d1449ec28, 0xc208050320, 0xc20802a340)
/home/vic/projects/go/src/github.com/ant0ine/go-json-rest/rest/handler.go:225 +0x3f
net/http.serverHandler.ServeHTTP(0xc208005380, 0x7f4d1449ec28, 0xc208050320, 0xc20802a340)
/usr/local/go/src/pkg/net/http/server.go:1673 +0x19f
net/http.(*conn).serve(0xc20804e180)
/usr/local/go/src/pkg/net/http/server.go:1174 +0xa7e
created by net/http.(*Server).Serve
/usr/local/go/src/pkg/net/http/server.go:1721 +0x313
It turned out, I forgot to start the path with /
. It would be nice to ensure that the path is valid.
When running the CORS example from the readme, the header in the response is:
Access-Control-Max-Age: ฐ
instead of:
Access-Control-Max-Age: 3600
Please tag a release (any version is fine) so that package maintainers can pull directly from github without having to create a release tarball on their own.
Concatenating the method and the path in the router feels kind of hacky, maybe go-urlrouter should evolve to take the method as parameter. Or just document this practice in urlrouter ?
I have some optional bits of code in my app that enable or disable groups or routes dynamically. To realize this, I have to make my plugins generate lists of routes everywhere and then concatenate them in my initialization code.
While I can easily continue to maintain lists of routes (right now, I build a global list), I'd much rather consider the handler to be the "container" of the routes (much like net/http does with a ServeMux and handlers). This is pretty trivial, and I'd gladly write it if you'll accept the patch.
use json.UnMarshalIndent. Where should be the option ?
Remove the use of req.UriForWithParams in examples/simple, to keep it simple and identical to the example of the documentation.
And instead provide an example showing an hypermedia payload built with req.UriForWithParams
Per the specification at http://www.w3.org/TR/cors/#resource-sharing-check the string "null" is a valid value for the header Origin.
It's sent by the browser when there is a redirect to a different origin, and is currently sent (at least by firefox and chrome) when the origin is "file:"
Hi!
Ive been starting to use go-json-rest and thanks Antoine for the great API!
But I would like to know how I can easier can control the logging, for example to add a new custom key/value to the json logger. It seems also that the "remoteuser" IP is not working anywhere. Some examples on how to make some custom logger would be great, or how to separate access logs from error logs (apache style).
The ResourceHandler should support transparent gzip encoding, configured by a the flag EnableGzip bool in the struct.
I specified my route like this:
rest.RouteObjectMethod("GET", "/ip/:ip", &api, "IpGet"),
This route works for this url /ip/ab.
But not for /ip/a.b (dotted string).
How to create route for dotted string?
Thanks.
In order to be as close as possible to the standard net/http, here is a possible API change:
Instead of subclassing http.Request and http.ResponseWriter, the framework can provide a third object rest.Helper
The signature of a endpoint method would be:
func Get(w http.ResponseWriter, r http.Request, h rest.Helper) {
}
Use of standard net/http methods would be very easy, example:
NotFound(w, r) // unchanged
The implementation would look like this:
type Helper struct {
w http.ResponseWriter
r http.Request
PathParams map[string]string
}
func (self *Helper) WriteJson(v interface{}) error {
}
func (self *Helper) PathParam(name string) string {
}
func (self *Helper) DecodeJsonPayload(v interface{}) error {
}
If route is &Route{"GET", "/r/:id/", ...}
Having a dot in the path param returns a 404
$ curl "http://localhost:8080/r/123.456/"
I can submit a pull request if you can point me in the right direction on how to fix this please.
CORS is now essential to any REST framework.
If it's possible to implement it right on top of Go-Json-Rest, but it is a lot of work.
The framework should make that easy.
for 1 serving the OPTIONS requests
a) intercept all OPTIONS requests and respond
+ simple
- sucks to not have any 404 on OPTIONS
b) loop over the Routes and create the OPTIONS routes in the router
- additional complexity
c) use the pathMatched result from the router
+ already there
+ no additional router complexity
+ still all the 404
=> lets go with c)
for 2, 3, 4, code idea
type CorsHeaders struct {
AccessControlAllowOrigin string
AccessControlAllowCredentials string
AccessControlExposeHeaders string
AccessControlMaxAge string
AccessControlAllowMethods string
AccessControlAllowHeaders string
}
type ResourceHandler struct {
...
// if nil is returned an error response is created to reject the request
EnableCors func(request *Request) *CorsHeaders
}
// in ServeHTTP
if pathMatched {
if method == OPTIONS {
ServePreFlightHTTP
...
}
func ServePreFlightHTTP {
// CORS is enabled, just do nothing, and let the responseWriter
// write the cors headers
}
Links:
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control
http://www.w3.org/TR/cors/
In commit c1bb041 you broke setting Content-Encoding: gzip
when compressing the response (again).
Right now there is no content type check. Even if the json content-type should be "application/json", a lot of other are in use. I think the framework should be tolerant about what the client uses.
This feature is disabled by default. It is useful mostly in PROD. But you probably don't want to share these info with the world.
Should this framework provide a way to enable AND restrict the access to /.status ?
Or is it something that should be handled outside ?
Including a vhost (hostname and port) in the routes results in a nil pointer dereference when requests, any request, arrive. For example:
package main
import (
"net/http"
"github.com/ant0ine/go-json-rest"
)
type User struct {
Id string
Name string
}
func GetUser(w *rest.ResponseWriter, req *rest.Request) {
user := User{
Id: req.PathParam("id"),
Name: "Antoine",
}
w.WriteJson(&user)
}
func main() {
handler := rest.ResourceHandler{}
handler.SetRoutes(
rest.Route{"GET", "/users/:id", GetUser},
rest.Route{"GET", "europa.loc:8080/people/:id", GetUser},
)
http.ListenAndServe(":8080", &handler)
}
results in:
2014/02/18 16:14:02 http: panic serving 127.0.0.1:41373: runtime error: invalid memory address or nil pointer dereference
goroutine 3 [running]:
net/http.func·009()
/usr/local/go/src/pkg/net/http/server.go:1093 +0xae
runtime.panic(0x629c80, 0x8f02c8)
/usr/local/go/src/pkg/runtime/panic.c:248 +0x106
github.com/ant0ine/go-json-rest.(*env).setVar(0x0, 0xc210059270, 0x68a470, 0xa, 0x5cade0, ...)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/env.go:15 +0x186
github.com/ant0ine/go-json-rest.func·006(0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/recorder.go:36 +0xdc
github.com/ant0ine/go-json-rest.func·009(0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/timer.go:14 +0x83
github.com/ant0ine/go-json-rest.func·007(0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/status.go:15 +0x4b
github.com/ant0ine/go-json-rest.func·001(0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/gzip.go:42 +0x155
github.com/ant0ine/go-json-rest.func·005(0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/log.go:45 +0x51
github.com/ant0ine/go-json-rest.(*ResourceHandler).ServeHTTP(0xc2100379c0, 0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/home/vagrant/go/ext/src/github.com/ant0ine/go-json-rest/handler.go:254 +0xc6
net/http.serverHandler.ServeHTTP(0xc21001e730, 0x7f0db8501500, 0xc21000f5a0, 0xc210059270)
/usr/local/go/src/pkg/net/http/server.go:1597 +0x16e
net/http.(*conn).serve(0xc210058280)
/usr/local/go/src/pkg/net/http/server.go:1167 +0x7b7
created by net/http.(*Server).Serve
/usr/local/go/src/pkg/net/http/server.go:1644 +0x28b
when you access it via curl:
curl -X GET http://europa.loc:8080/people/bob
github.com/ant0ine/go-json-rest is the import path, but the package name is rest. This breaks the following convention:
Go's convention is that the package name is the last element of the import path: the package imported as "crypto/rot13" should be named rot13.
A particular fallout of this is that the handy goimports tool cannot be used with code employing go-json-rest, as it sees no uses of the go-json-rest package and removes the import.
Filtering in REST is usually done by adding parameters at the end of the URL with "?foo=bar&a=b"
Example: http://company.com/person?age=65&sex=male
Reference: http://stackoverflow.com/a/8807065/459050
This does not seem to work:
I have tried:
&rest.Route{"GET", "/person?age=:age", GetPersonsByAge},
But this causes a panic.
I have tried:
&rest.Route{"GET", "/person?age=:age", GetFilterPersons},
Does not cause a panic, but in the Handler req.PathParam("age") is always nil for URL: /person?age=42
The following returns null when the endpoint is called:
func (t *WebAppData) testRest(w rest.ResponseWriter, r *rest.Request) {
var array []int
if err := w.WriteJson(&array); err != nil {
log.Printf("Failed to write json: %v", err)
}
return
}
It shouldn't - it should return []. Similarly, an initialized map should return {} instead of null.
This is a common use case for REST APIs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.