Documentation ¶
Overview ¶
## go-rest A small and evil REST framework for Go
### Reflection, Go structs, and JSON marshalling FTW!
* go get github.com/ungerik/go-rest * import "github.com/ungerik/go-rest" * Documentation: http://go.pkgdoc.org/github.com/ungerik/go-rest * License: Public Domain
Download, build and run example:
go get github.com/ungerik/go-rest go install github.com/ungerik/go-rest/example && example
Small?
Yes, the framework consists of only three functions: HandleGET, HandlePOST, RunServer.
Evil?
Well, this package can be considered bad design because HandleGET and HandlePOST use dynamic typing to hide 36 combinations of handler function types to make the interface _easy_ to use. 36 static functions would have been more lines of code but dramatic _simpler_ in their individual implementations. So simple in fact, that there wouldn't be a point in abstracting them away in an extra framework. See this great talk about easy vs. simple: http://www.infoq.com/presentations/Simple-Made-Easy Rob Pike may also dislike this approach: https://groups.google.com/d/msg/golang-nuts/z4T_n4MHbXM/jT9PoYc6I1IJ So yes, this package can be called evil because it is an anti-pattern to all that is good and right about Go.
Why use it then? By maximizing dynamic code it is easy to use and reduces code. Yes, that introduces some internal complexity, but this complexity is still very low in absolute terms and thus easy to control and debug. The complexity of the dynamic code also does not spill over into the package users' code, because the arguments and results of the handler functions must be static typed and can't be interface{}.
Now let's have some fun:
HandleGET uses a handler function that returns a struct or string to create the GET response. Structs will be marshalled as JSON, strings will be used as body with auto-detected content type.
Format of GET handler:
func([url.Values]) ([struct|*struct|string][, error]) {}
Example:
type MyStruct struct { A in B string } rest.HandleGET("/data.json", func() *MyStruct { return &MyStruct{A: 1, B: "Hello World"} }) rest.HandleGET("/index.html", func() string { return "<!doctype html><p>Hello World" })
The GET handler function can optionally accept an url.Values argument and return an error as second result value that will be displayed as 500 internal server error if not nil.
Example:
rest.HandleGET("/data.json", func(params url.Values) (string, error) { v := params.Get("value") if v == "" { return nil, errors.New("Expecting GET parameter 'value'") } return "value = " + v, nil })
HandlePOST maps POST form data or a JSON document to a struct that is passed to the handler function. An error result from handler will be displayed as 500 internal server error message. An optional first string result will be displayed as a 200 response body with auto-detected content type.
Suported content types for POST requests are: * application/x-www-form-urlencoded * multipart/form-data * text/plain * application/json * application/xml
Format of POST handler:
func([*struct|url.Values]) ([struct|*struct|string],[error]) {}
Example:
rest.HandlePOST("/change-data", func(data *MyStruct) (err error) { // save data return err })
Both HandleGET and HandlePOST also accept one optional object argument. In that case handler is interpreted as a method of the type of object and called accordingly.
Example:
rest.HandleGET("/method-call", (*myType).MethodName, myTypeObject)
Index ¶
- Variables
- func GetJSON(addr string, out interface{}) error
- func GetJSONStrict(addr string, out interface{}) error
- func HandleGET(path string, handler interface{}, object ...interface{})
- func HandlePOST(path string, handler interface{}, object ...interface{})
- func RunServer(addr string, stop chan struct{})
Constants ¶
This section is empty.
Variables ¶
var ( // IndentJSON is the string with which JSON output will be indented. IndentJSON string // Log is a function pointer compatible to fmt.Println or log.Println. // The default value is log.Println. Log = log.Println // DontCheckRequestMethod disables checking for the correct // request method for a handler, which would result in a // 405 error if not correct. DontCheckRequestMethod bool )
Functions ¶
func GetJSONStrict ¶
GetJSONStrict sends a HTTP GET request to addr and unmarshalles the JSON response to out. Returns an error if Content-Type is not application/json.
func HandleGET ¶
func HandleGET(path string, handler interface{}, object ...interface{})
HandleGET registers a HTTP GET handler for path. handler is a function with an optional url.Values argument.
If the first result value of handler is a struct or struct pointer, then the struct will be marshalled as JSON response. If the first result value fo handler is a string, then it will be used as response body with an auto-detected content type. An optional second result value of type error will create a 500 internal server error response if not nil. All non error responses will use status code 200.
A single optional argument can be passed as object. In that case handler is interpreted as a method and object is the address of an object with such a method.
Format of GET handler:
func([url.Values]) ([struct|*struct|string][, error]) {}
func HandlePOST ¶
func HandlePOST(path string, handler interface{}, object ...interface{})
HandlePOST registers a HTTP POST handler for path. handler is a function that takes a struct pointer or url.Values as argument.
If the request content type is text/plain, then only a struct pointer is allowed as handler argument and the request body will be interpreted as JSON and unmarshalled to a new struct instance.
If the request content type multipart/form-data, then only a struct pointer is allowed as handler argument and a file named JSON will be unmarshalled to a new struct instance.
If the request content type is empty or application/x-www-form-urlencoded and the handler argument is of type url.Values, then the form values will be passed directly as url.Values. If the handler argument is a struct pointer and the form contains a single value named "JSON", then the value will be interpreted as JSON and unmarshalled to a new struct instance. If there are multiple form values, then they will be set at struct fields with exact matching names.
If the first result value of handler is a struct or struct pointer, then the struct will be marshalled as JSON response. If the first result value fo handler is a string, then it will be used as response body with an auto-detected content type. An optional second result value of type error will create a 500 internal server error response if not nil. All non error responses will use status code 200.
A single optional argument can be passed as object. In that case handler is interpreted as a method and object is the address of an object with such a method.
Format of POST handler:
func([*struct|url.Values]) ([struct|*struct|string][, error]) {}
Types ¶
This section is empty.