Documentation ¶
Overview ¶
Package websrv provides a stylized way to write HTTP handlers and run an HTTP server.
Overview ¶
An HTTP server using package websrv registers handlers by calling Handle(pattern, handler). The top-level Handler is a standard HTTP handler that dispatches to the registered websrv handlers. Handler itself must be registered explicitly with the standard HTTP package:
package main import ( "net/http" "github.com/TheJumpCloud/rsc/websrv" ) func main() { websrv.Handle("/doc/{DocID}", new(docRequest)) http.Handle("/", websrv.Handler) websrv.Serve() }
This package does not automatically register websrv.Handler because client code might wish to use its own top-level handler to pick off some requests, or to add custom logging or authentication before invoking websrv.Handler.
Patterns ¶
The first argument to Handle is a pattern specifying the set of paths for which the handler should be invoked.
The simplest pattern is a path, like /hello/world. Such a path matches exactly that URL and no others. Like in package http, the path may begin with a host name to restrict the matches to URLs on a specific host.
A pattern may specify a wildcard - a name enclosed in braces - for any path element. For example, /hello/{Name} matches /hello/world, /hello/ken, and /hello/123, but not /hello/two/elements.
Handlers ¶
A handler is a value with any of these four methods:
Get(ctxt *Context) Post(ctxt *Context) Put(ctxt *Context) Delete(ctxt *Context)
If an incoming request maps to a handler without the requested method (for example, a DELETE request arrives for a handler that implements only Get), the server replies with an HTTP "method not allowed" error, without using the handler at all.
If the handler object is a pointer to a struct, additional processing happens before invoking the corresponding service method. First, the server makes a copy of the struct (or, if the pointer is nil, allocates a zero struct) and uses a pointer to that copy, not the original, when invoking the handler. This gives each request some local storage. Second, after making the copy, the server looks for fields with names matching the wildcards, and for each such field copies the corresponding path element into the field. The path element must be convertible into the field.
For example, consider:
type Hello struct { Name string } type Page struct { Format string ID int } websrv.Handle("/hello/{Name}", (*Hello)(nil)) websrv.Handle("/page/{ID}", &Page{Format: "text"})
The server will prepare the receiver for the URL /hello/world by allocating a new Hello struct and setting its Name field to "world". The server will prepare the receiver for the URL /page/5 by making a copy of the prototype Page struct and setting ID to 5, so that the receiver is effectively &Page{Format: "text", ID: 5}.
After preparing the receiver from the URL, the server turns to the posted form data and URL query parameters. A form value or query parameter with a name matching a struct field will be copied into that struct field. For example, the URL /page/10?Format=html would result in a receiver value &Page{Format: "html", ID: 10}. URL path wildcards have the highest priority: /page/10?ID=11 matching /page/{ID} ignores the ID=11, because the wildcard has already claimed ID. Otherwise, posted field values take precedence over query parameters, and the first value is the one recorded. An exception to that rule, a field of slice type records all vales, first from the posted form data and then from the URL query.
If a struct field has a tag with a "websrv" key, that key's value specifies a comma-separated list in which the first item is a name to use instead of the struct field name, and the remainder are attributes. The only attribute is "post", which indicates that a field must be filled using posted data, not URL query parameters.
For example:
type Page struct { Format string `websrv:"fmt"` ID int }
will match /page/10?fmt=html instead of /page/10?Format=html. If the tag said "fmt,post", the fmt= in the URL would be ignored entirely, and only a posted fmt value could be recorded.
As a final step in preparing the receiver, if the posted body has content type "application/json", the body is treated as JSON and unmarshaled into the receiver using the standard encoding/json package. As such it does not respect websrv tags, and it overwrites values set by URL patterns or query parameters. This form is intended to support using jQuery to post JSON objects.
After completing that initialization (or skipping it, if the receiver is not a pointer to a struct), the service invokes the corresponding method. During that invocation, the Context argument provides access to additional request details and also enables sending the response.
Contexts ¶
A Context represents both the incoming HTTP request and the response being prepared. It provides access to the request as ctxt.Request, and it implements http.ResponseWriter, meaning it has Header, Write, and WriteHeader methods. However, by default the context buffers the response in memory, only sending it when the handler method returns. To bypass the buffer, invoke the DisableWriteBuffer method.
If a handler panics, the server discards the response buffered in the Context and instead sends an HTTP 500 error containing the panic text and a stack trace.
Index ¶
- Variables
- func Handle(pattern string, fn interface{})
- func Serve(addr string)
- type Context
- func (ctxt *Context) DisableWriteBuffer()
- func (ctxt *Context) Header() http.Header
- func (ctxt *Context) Redirect(url string)
- func (ctxt *Context) ServeFile(path string)
- func (ctxt *Context) ServeJSON(data interface{})
- func (ctxt *Context) Write(p []byte) (n int, err error)
- func (ctxt *Context) WriteHeader(status int)
Constants ¶
This section is empty.
Variables ¶
var Handler http.Handler = http.HandlerFunc(handle)
Handler is an http.Handler that dispatches to the registered websrv handlers.
Functions ¶
Types ¶
type Context ¶
A Context provides access to an incoming HTTP request and collects the outgoing response. By default, the response is buffered in memory until the handler returns.
func (*Context) DisableWriteBuffer ¶
func (ctxt *Context) DisableWriteBuffer()
DisableWriteBuffer disables the response write buffer. Any buffered writes are sent to the underlying ResponseWriter, and any future writes bypass the buffer.
func (*Context) ServeJSON ¶
func (ctxt *Context) ServeJSON(data interface{})
ServeJSON serves the request using the JSON encoding of the given data. It sets the content type of the response to "application/json".
func (*Context) WriteHeader ¶
WriteHeader writes the HTTP header, with the given status.