Documentation ¶
Overview ¶
Package web is a full-featured HTTP router and server for Go applications, suitable for serving static files, REST APIs, and more.
Web includes these features:
- HTTP range support
- Static file serving
- Directory listings
- Websockets
- Per-IP rate limiting
- Per-request contextual data
Web offers four APIs for developers to choose from:
API ¶
API provides everything you need to build poweful REST APIs using JSON. Define your routes and easily accept and return data as JSON.
Example:
router := web.New("[::]:8080") router.API.Get("/users", getUsers, options) router.API.Get("/users/:username", getUsers, options)
For more information, see the documentation of web.API.
HTTPEasy ¶
HTTPEasy provides a straightforward interface to accept HTTP requets and return data.
Example:
router := web.New("[::]:8080") router.HTTPEasy.Get("/index.html", getIndex, options) router.HTTPEasy.Get("/cat.jpg", getKitty, options)
For more information, see the documentation of web.HTTPEasy.
HTTP ¶
HTTP provides full access to the original HTTP request, allowing you total control over the response, whatever that may be.
Example:
router := web.New("[::]:8080") router.HTTP.Get("/index.html", getIndex, options) router.HTTP.Get("/cat.jpg", getKitty, options)
For more information, see the documentation of web.HTTP.
Websockets ¶
This package also provides a wrapper for github.com/gorilla/websocket
Example:
router := web.New("[::]:8080") router.Socket("/ws", handleSocket, options)
Example (Authentication) ¶
package main import ( "net/http" "time" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type User struct { Username string `json:"username"` } // Login loginHandle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { // Do any authentication logic here // Assuming the user authenticated successfully... return true, &web.APIResponse{ Cookies: []http.Cookie{ { Name: "session", Value: "1", Path: "/", Expires: time.Now().AddDate(0, 0, 1), }, }, }, nil } unauthenticatedOptions := web.HandleOptions{} server.API.GET("/login", loginHandle, unauthenticatedOptions) // Get User Info getUserHandle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { user := request.UserData.(User) return user, nil, nil } authenticatedOptions := web.HandleOptions{ // The authenticate method is where you validate that a request if from an authenticated, or simple "logged in" // user. In this example, we validate that a cookie is present. // Any data returned by this method is provided into the request handler as Request.UserData // Returning nil results in a HTTP 403 response AuthenticateMethod: func(request *http.Request) interface{} { cookie, err := request.Cookie("session") if err != nil || cookie == nil { return nil } if cookie.Value != "1" { return nil } return map[string]string{ "foo": "bar", } }, } // Notice that we used a different HandleOptions instance with our AuthenticateMethod // an options without any AuthenticateMethod is considered unauthenticated server.API.GET("/user", getUserHandle, authenticatedOptions) if err := server.Start(); err != nil { panic(err) } }
Output:
Example (File) ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { f, err := os.Open("/foo/bar") if err != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Reader: f, } } options := web.HandleOptions{} server.HTTPEasy.GET("/file", handle, options) if err := server.Start(); err != nil { panic(err) } }
Output:
Example (Json) ¶
package main import ( "time" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { return time.Now().Unix(), nil, nil } options := web.HandleOptions{} server.API.GET("/time", handle, options) if err := server.Start(); err != nil { panic(err) } }
Output:
Example (Ratelimit) ¶
package main import ( "net/http" "time" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") // Restrict each connecting IP address to a maximum of 5 requests per second server.Options.MaxRequestsPerSecond = 5 // Handle called when a request is rejected due to rate limiting server.RateLimitedHandler = func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(429) w.Write([]byte("Too many requests")) } handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { return time.Now().Unix(), nil, nil } options := web.HandleOptions{} server.API.GET("/time", handle, options) if err := server.Start(); err != nil { panic(err) } }
Output:
Example (Unixsocket) ¶
package main import ( "net" "time" "github.com/ecnepsnai/web" ) func main() { l, err := net.Listen("unix", "/example.socket") if err != nil { panic(err) } server := web.NewListener(l) handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { return time.Now().Unix(), nil, nil } options := web.HandleOptions{} server.API.GET("/time", handle, options) if err := server.Start(); err != nil { panic(err) } }
Output:
Example (Websocket) ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type questionType struct { Name string } type answerType struct { Reply string } handle := func(request web.Request, conn *web.WSConn) { question := questionType{} if err := conn.ReadJSON(&question); err != nil { return } reply := answerType{ Reply: "Hello, " + question.Name, } if err := conn.WriteJSON(&reply); err != nil { return } } options := web.HandleOptions{} server.Socket("/greeting", handle, options) if err := server.Start(); err != nil { panic(err) } }
Output:
Index ¶
- Variables
- func RealRemoteAddr(r *http.Request) net.IP
- type API
- func (a API) DELETE(path string, handle APIHandle, options HandleOptions)
- func (a API) GET(path string, handle APIHandle, options HandleOptions)
- func (a API) HEAD(path string, handle APIHandle, options HandleOptions)
- func (a API) OPTIONS(path string, handle APIHandle, options HandleOptions)
- func (a API) PATCH(path string, handle APIHandle, options HandleOptions)
- func (a API) POST(path string, handle APIHandle, options HandleOptions)
- func (a API) PUT(path string, handle APIHandle, options HandleOptions)
- type APIHandle
- type APIResponse
- type Decoder
- type Error
- type HTTP
- func (h HTTP) DELETE(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) GET(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) HEAD(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) OPTIONS(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) PATCH(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) POST(path string, handle HTTPHandle, options HandleOptions)
- func (h HTTP) PUT(path string, handle HTTPHandle, options HandleOptions)
- type HTTPEasy
- func (h HTTPEasy) DELETE(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) GET(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) GETHEAD(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) HEAD(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) OPTIONS(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) PATCH(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) POST(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) PUT(path string, handle HTTPEasyHandle, options HandleOptions)
- func (h HTTPEasy) Static(path string, directory string)
- type HTTPEasyHandle
- type HTTPHandle
- type HTTPResponse
- type HandleOptions
- type JSONResponse
- type MockRequestParameters
- type Request
- type Server
- type ServerOptions
- type SocketHandle
- type WSConn
Examples ¶
- Package (Authentication)
- Package (File)
- Package (Json)
- Package (Ratelimit)
- Package (Unixsocket)
- Package (Websocket)
- API.DELETE
- API.GET
- API.HEAD
- API.OPTIONS
- API.PATCH
- API.POST
- API.PUT
- HTTP.DELETE
- HTTP.GET
- HTTP.HEAD
- HTTP.OPTIONS
- HTTP.PATCH
- HTTP.POST
- HTTP.PUT
- HTTPEasy.DELETE
- HTTPEasy.GET
- HTTPEasy.GETHEAD
- HTTPEasy.HEAD
- HTTPEasy.OPTIONS
- HTTPEasy.PATCH
- HTTPEasy.POST
- HTTPEasy.PUT
- HTTPEasy.Static
- Request.DecodeJSON
- Request.RealRemoteAddr
- Server.Socket
- ValidationError
Constants ¶
This section is empty.
Variables ¶
var CommonErrors = struct { NotFound *Error BadRequest *Error Unauthorized *Error Forbidden *Error ServerError *Error TooManyRequests *Error }{ NotFound: &Error{ Code: 404, Message: "Not Found", }, BadRequest: &Error{ Code: 400, Message: "Bad Request", }, Unauthorized: &Error{ Code: 403, Message: "Unauthorized", }, Forbidden: &Error{ Code: 403, Message: "Forbidden", }, ServerError: &Error{ Code: 500, Message: "Server Error", }, TooManyRequests: &Error{ Code: 429, Message: "Too Many Requests", }, }
CommonErrors are common errors types suitable for API endpoints
Functions ¶
func RealRemoteAddr ¶ added in v1.12.0
RealRemoteAddr will try to get the real IP address of the incoming connection taking proxies into consideration. This function looks for the `X-Real-IP`, `X-Forwarded-For`, and `CF-Connecting-IP` headers, and if those don't exist will return the remote address of the connection.
Will never return nil, if it is unable to get a valid address it will return 0.0.0.0
Types ¶
type API ¶
type API struct {
// contains filtered or unexported fields
}
API describes a JSON API server. API handles return data or an error, and all responses are wrapped in a common response object; web.JSONResponse.
func (API) DELETE ¶
func (a API) DELETE(path string, handle APIHandle, options HandleOptions)
DELETE register a new HTTP DELETE request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] return map[string]string{ "username": username, }, nil, nil } server.API.DELETE("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) GET ¶
func (a API) GET(path string, handle APIHandle, options HandleOptions)
GET register a new HTTP GET request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] return map[string]string{ "username": username, }, nil, nil } server.API.GET("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) HEAD ¶
func (a API) HEAD(path string, handle APIHandle, options HandleOptions)
HEAD register a new HTTP HEAD request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { return nil, nil, nil } server.API.HEAD("/users/user/", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) OPTIONS ¶
func (a API) OPTIONS(path string, handle APIHandle, options HandleOptions)
OPTIONS register a new HTTP OPTIONS request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { return nil, nil, nil } server.API.OPTIONS("/users/user/", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) PATCH ¶
func (a API) PATCH(path string, handle APIHandle, options HandleOptions)
PATCH register a new HTTP PATCH request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type userRequestType struct { FirstName string `json:"first_name"` } handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] params := userRequestType{} if err := request.DecodeJSON(¶ms); err != nil { return nil, nil, err } return map[string]string{ "first_name": params.FirstName, "username": username, }, nil, nil } server.API.PATCH("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) POST ¶
func (a API) POST(path string, handle APIHandle, options HandleOptions)
POST register a new HTTP POST request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type userRequestType struct { FirstName string `json:"first_name"` } handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] params := userRequestType{} if err := request.DecodeJSON(¶ms); err != nil { return nil, nil, err } return map[string]string{ "first_name": params.FirstName, "username": username, }, nil, nil } server.API.POST("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (API) PUT ¶
func (a API) PUT(path string, handle APIHandle, options HandleOptions)
PUT register a new HTTP PUT request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type userRequestType struct { FirstName string `json:"first_name"` } handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] params := userRequestType{} if err := request.DecodeJSON(¶ms); err != nil { return nil, nil, err } return map[string]string{ "first_name": params.FirstName, "username": username, }, nil, nil } server.API.PUT("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
type APIHandle ¶
type APIHandle func(request Request) (interface{}, *APIResponse, *Error)
APIHandle describes a method signature for handling an API request
type APIResponse ¶ added in v1.11.0
type APIResponse struct { // Additional headers to append to the response. Headers map[string]string // Cookies to set on the response. Cookies []http.Cookie }
APIResponse describes additional response properties for API handles
type Error ¶
Error describes an API error object
func ValidationError ¶
ValidationError convenience method to make a error object for validation errors
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] return nil, nil, web.ValidationError("No user with username %s", username) } server.API.GET("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
type HTTP ¶
type HTTP struct {
// contains filtered or unexported fields
}
HTTP describes a HTTP server. HTTP handles are exposed to the raw http request and response writers.
func (HTTP) DELETE ¶
func (h HTTP) DELETE(path string, handle HTTPHandle, options HandleOptions)
DELETE register a new HTTP DELETE request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { username := r.Parameters["username"] w.Header().Set("X-Username", username) w.WriteHeader(200) } server.HTTP.DELETE("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) GET ¶
func (h HTTP) GET(path string, handle HTTPHandle, options HandleOptions)
GET register a new HTTP GET request handle
Example ¶
package main import ( "fmt" "io" "net/http" "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { f, _ := os.Open("/foo/bar") info, _ := f.Stat() w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size())) io.Copy(w, f) } server.HTTP.GET("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) HEAD ¶
func (h HTTP) HEAD(path string, handle HTTPHandle, options HandleOptions)
HEAD register a new HTTP HEAD request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { w.Header().Set("X-Fancy-Header", "Some value") w.WriteHeader(204) } server.HTTP.HEAD("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) OPTIONS ¶
func (h HTTP) OPTIONS(path string, handle HTTPHandle, options HandleOptions)
OPTIONS register a new HTTP OPTIONS request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { w.Header().Set("X-Fancy-Header", "Some value") w.WriteHeader(200) } server.HTTP.OPTIONS("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) PATCH ¶
func (h HTTP) PATCH(path string, handle HTTPHandle, options HandleOptions)
PATCH register a new HTTP PATCH request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { username := r.Parameters["username"] w.Header().Set("X-Username", username) w.WriteHeader(200) } server.HTTP.PATCH("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) POST ¶
func (h HTTP) POST(path string, handle HTTPHandle, options HandleOptions)
POST register a new HTTP POST request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { username := r.Parameters["username"] w.Header().Set("X-Username", username) w.WriteHeader(200) } server.HTTP.POST("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTP) PUT ¶
func (h HTTP) PUT(path string, handle HTTPHandle, options HandleOptions)
PUT register a new HTTP PUT request handle
Example ¶
package main import ( "net/http" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(w http.ResponseWriter, r web.Request) { username := r.Parameters["username"] w.Header().Set("X-Username", username) w.WriteHeader(200) } server.HTTP.PUT("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
type HTTPEasy ¶ added in v1.11.0
type HTTPEasy struct {
// contains filtered or unexported fields
}
HTTPEasy describes a simple to use HTTP router. HTTPEasy handles are expected to return a reader and specify the content type and length themselves.
HTTP abstracts many features away from the caller, providing a simpler experience when a only a simple HTTP server is needed. If you require more control, use the HTTP router.
The HTTPEasy server supports HTTP range requests, should the client request it and the application provide a supported Reader io.ReadSeekCloser.
func (HTTPEasy) DELETE ¶ added in v1.11.0
func (h HTTPEasy) DELETE(path string, handle HTTPEasyHandle, options HandleOptions)
DELETE register a new HTTP DELETE request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { username := request.Parameters["username"] return web.HTTPResponse{ Headers: map[string]string{ "X-Username": username, }, } } server.HTTPEasy.DELETE("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) GET ¶ added in v1.11.0
func (h HTTPEasy) GET(path string, handle HTTPEasyHandle, options HandleOptions)
GET register a new HTTP GET request handle
Example ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { f, err := os.Open("/foo/bar") info, ierr := f.Stat() if err != nil || ierr != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Reader: f, // The file will be closed automatically ContentType: "text/plain", ContentLength: uint64(info.Size()), } } server.HTTPEasy.GET("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) GETHEAD ¶ added in v1.11.0
func (h HTTPEasy) GETHEAD(path string, handle HTTPEasyHandle, options HandleOptions)
GETHEAD registers both a HTTP GET and HTTP HEAD request handle. Equal to calling HTTPEasy.GET and HTTPEasy.HEAD.
Handle responses can always return a reader, it will automatically be ignored for HEAD requests.
Example ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { f, err := os.Open("/foo/bar") info, ierr := f.Stat() if err != nil || ierr != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Reader: f, // the file will not be read for HTTP HEAD requests, but it will be closed. ContentType: "text/plain", ContentLength: uint64(info.Size()), } } server.HTTPEasy.GETHEAD("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) HEAD ¶ added in v1.11.0
func (h HTTPEasy) HEAD(path string, handle HTTPEasyHandle, options HandleOptions)
HEAD register a new HTTP HEAD request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { return web.HTTPResponse{ Headers: map[string]string{ "X-Fancy-Header": "some value", }, } } server.HTTPEasy.HEAD("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) OPTIONS ¶ added in v1.11.0
func (h HTTPEasy) OPTIONS(path string, handle HTTPEasyHandle, options HandleOptions)
OPTIONS register a new HTTP OPTIONS request handle
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { return web.HTTPResponse{ Headers: map[string]string{ "X-Fancy-Header": "some value", }, } } server.HTTPEasy.OPTIONS("/users/user", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) PATCH ¶ added in v1.11.0
func (h HTTPEasy) PATCH(path string, handle HTTPEasyHandle, options HandleOptions)
PATCH register a new HTTP PATCH request handle
Example ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { username := request.Parameters["username"] f, err := os.Open("/foo/bar") if err != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Headers: map[string]string{ "X-Username": username, }, Reader: f, } } server.HTTPEasy.PATCH("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) POST ¶ added in v1.11.0
func (h HTTPEasy) POST(path string, handle HTTPEasyHandle, options HandleOptions)
POST register a new HTTP POST request handle
Example ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { username := request.Parameters["username"] f, err := os.Open("/foo/bar") if err != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Headers: map[string]string{ "X-Username": username, }, Reader: f, } } server.HTTPEasy.POST("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) PUT ¶ added in v1.11.0
func (h HTTPEasy) PUT(path string, handle HTTPEasyHandle, options HandleOptions)
PUT register a new HTTP PUT request handle
Example ¶
package main import ( "os" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) web.HTTPResponse { username := request.Parameters["username"] f, err := os.Open("/foo/bar") if err != nil { return web.HTTPResponse{ Status: 500, } } return web.HTTPResponse{ Headers: map[string]string{ "X-Username": username, }, Reader: f, } } server.HTTPEasy.PUT("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (HTTPEasy) Static ¶ added in v1.11.0
Static registers a GET and HEAD handle for all requests under path to serve any files matching the directory.
For example:
directory = /usr/share/www/ path = /static/ Request for '/static/image.jpg' would read file '/usr/share/www/image.jpg'
Will panic if any handle is registered under path. Attempting to register a new handle under path after calling Static will panic.
Caching will be enabled by default for all files served by this router. The mtime of the file will be used for the Last-Modified date.
By default, the server will use the file extension (if any) to determine the MIME type for the response.
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") server.HTTPEasy.Static("/static/*", "/path/to/static/files") server.Start() }
Output:
type HTTPEasyHandle ¶ added in v1.11.0
type HTTPEasyHandle func(request Request) HTTPResponse
HTTPEasyHandle describes a method signature for handling an HTTP request
type HTTPHandle ¶
type HTTPHandle func(w http.ResponseWriter, r Request)
HTTPHandle describes a method signature for handling an HTTP request
type HTTPResponse ¶ added in v1.9.0
type HTTPResponse struct { // The reader for the response. Will be closed when the HTTP response is finished. Can be nil. // // If a io.ReadSeekCloser is provided then ranged data may be provided for a HTTP range request. Reader io.ReadCloser // The status code for the response. If 0 then 200 is implied. Status int // Additional headers to append to the response. Headers map[string]string // Cookies to set on the response. Cookies []http.Cookie // The content type of the response. Will overwrite any 'content-type' header in Headers. ContentType string // The length of the content. Will overwrite any 'content-length' header in Headers. ContentLength uint64 }
HTTPResponse describes a HTTP response
type HandleOptions ¶
type HandleOptions struct { // AuthenticateMethod method called to determine if a request is properly authenticated or not. If a method is // provided, then it is called for each incoming request. The value returned by this method is passed as the // UserData field of a [web.Request]. Returning nil signals an unauthenticated request, which will be handled by // the UnauthorizedMethod (if provided) or a default handle. If the AuthenticateMethod is not provided, then the // UserData field is nil. AuthenticateMethod func(request *http.Request) interface{} // PreHandle is an optional method that is called immediately upon receiving the HTTP request, before authentication // and before rate limit checks. This method allows servers to provide early handling of a request before any // processing happens. // // The returned error is only used as a nil check, the value of any error isn't used. If an error is returned then // no more processing is performed. It is assumed that a response will have been written to w. // // If nil is returned then the request will continue normally, no status should have been written to w. Any headers // added may be overwritten by the handle. PreHandle func(w http.ResponseWriter, request *http.Request) error // which allows you to customize the response seen by the user. // If omitted, a default handle is used. UnauthorizedMethod func(w http.ResponseWriter, request *http.Request) // MaxBodyLength defines the maximum length accepted for any HTTP request body. Requests that exceed this limit will // receive a "413 Payload Too Large" response. The default value of 0 will not reject requests with large bodies. MaxBodyLength uint64 // DontLogRequests if true then requests to this handle are not logged DontLogRequests bool }
HandleOptions describes options for a route
type JSONResponse ¶
type JSONResponse struct { // The actual data of the response Data interface{} `json:"data,omitempty"` // If an error occured, details about the error Error *Error `json:"error,omitempty"` }
JSONResponse describes an API response object
type MockRequestParameters ¶ added in v1.11.2
type MockRequestParameters struct { // User data to be passed into the handler. May be nil. UserData interface{} // URL parameters (not query parameters) to be populated into the request.Params object in the handler. May be nil. Parameters map[string]string // Object to be encoded with JSON as the body. May be nil. Exclusive to Body. JSONBody interface{} // Body data. May be nil. Exclusive to JSONBody. Body io.ReadCloser // Optional HTTP request to pass to the handler. Request *http.Request }
Parameters for creating a mock request for uses in tests
type Request ¶
type Request struct { // The original HTTP request HTTP *http.Request // URL path parameters (not query parameters). Keys do not include the ':' or '*'. Parameters map[string]string // User data provided from the result of the AuthenticateRequest method on the handle options UserData any }
Request describes an API request
func MockRequest ¶
func MockRequest(parameters MockRequestParameters) Request
MockRequest will generate a mock request for testing your handlers. Will panic for invalid parameters.
func (Request) DecodeJSON ¶ added in v1.7.0
DecodeJSON unmarshal the JSON body to the provided interface.
Equal to calling:
r.Decode(v, json.NewDecoder(r.HTTP.Body))
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type userRequestType struct { FirstName string `json:"first_name"` } handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { username := request.Parameters["username"] params := userRequestType{} if err := request.DecodeJSON(¶ms); err != nil { return nil, nil, err } return map[string]string{ "first_name": params.FirstName, "username": username, }, nil, nil } server.API.POST("/users/user/:username", handle, web.HandleOptions{}) server.Start() }
Output:
func (Request) RealRemoteAddr ¶ added in v1.12.0
RealRemoteAddr will try to get the real IP address of the incoming connection taking proxies into consideration. This function looks for the `X-Real-IP`, `X-Forwarded-For`, and `CF-Connecting-IP` headers, and if those don't exist will return the remote address of the connection.
Will never return nil, if it is unable to get a valid address it will return 0.0.0.0
Example ¶
package main import ( "fmt" "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") handle := func(request web.Request) (interface{}, *web.APIResponse, *web.Error) { clientAddr := request.RealRemoteAddr().String() fmt.Printf("%s\n", clientAddr) return clientAddr, nil, nil } server.API.POST("/ip/my_ip", handle, web.HandleOptions{}) server.Start() }
Output:
type Server ¶
type Server struct { // The socket address that the server is listening on. Only populated if the server was created with web.New(). BindAddress string // The port that this server is listening on. Only populated if the server was created with web.New(). ListenPort uint16 // The JSON API server. API handles return data or an error, and all responses are wrapped in a common // response object; [web.JSONResponse]. API API // HTTPEasy describes a easy HTTP server. HTTPEasy handles are expected to return a reader and specify the content // type and length themselves. // // The HTTPEasy server supports HTTP range requests, should the client request it and the application provide a // supported Reader [io.ReadSeekCloser]. HTTPEasy HTTPEasy // The HTTP server. HTTP handles are exposed to the raw http request and response writers. HTTP HTTP // The handler called when a request that does not match a registered path occurs. Defaults to a plain // HTTP 404 with "Not found" as the body. NotFoundHandler func(w http.ResponseWriter, r *http.Request) // The handler called when a request that did match a router but with the incorrect method occurs. Defaults to a // plain HTTP 405 with "Method not allowed" as the body. MethodNotAllowedHandler func(w http.ResponseWriter, r *http.Request) // The handler called when a request exceed the configured maximum per second limit. Defaults to a plain HTTP 429 // with "Too many requests" as the body. RateLimitedHandler func(w http.ResponseWriter, r *http.Request) // Additional options for the server Options ServerOptions // contains filtered or unexported fields }
Server describes an web server
func New ¶
New create a new server object that will bind to the provided address. Does not accept incoming connections until the server is started. Bind address must be in the format of "address:port", such as "localhost:8080" or "0.0.0.0:8080".
func NewListener ¶ added in v1.10.0
NewListener creates a new server object that will use the given listener. Does not accept incoming connections until the server is started.
func (*Server) Socket ¶ added in v1.4.0
func (s *Server) Socket(path string, handle SocketHandle, options HandleOptions)
Socket register a new websocket server at the given path
Example ¶
package main import ( "github.com/ecnepsnai/web" ) func main() { server := web.New("127.0.0.1:8080") type questionType struct { Name string } type answerType struct { Reply string } handle := func(request web.Request, conn *web.WSConn) { question := questionType{} if err := conn.ReadJSON(&question); err != nil { return } reply := answerType{ Reply: "Hello, " + question.Name, } if err := conn.WriteJSON(&reply); err != nil { return } } options := web.HandleOptions{} server.Socket("/greeting", handle, options) server.Start() }
Output:
type ServerOptions ¶ added in v1.9.0
type ServerOptions struct { // Specify the maximum number of requests any given client IP address can make per second. Requests that are rate // limited will call the RateLimitedHandler, which you can override to customize the response. // Setting this to 0 disables rate limiting. MaxRequestsPerSecond int // The level to use when logging out HTTP requests. Maps to github.com/ecnepsnai/logtic levels. Defaults to Debug. RequestLogLevel logtic.LogLevel // If true then the server will not try to reply with chunked data for a HTTP range request IgnoreHTTPRangeRequests bool }
type SocketHandle ¶ added in v1.4.0
SocketHandle describes a method signature for handling a HTTP websocket request