Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame^] | 1 | /* |
| 2 | Package restful , a lean package for creating REST-style WebServices without magic. |
| 3 | |
| 4 | WebServices and Routes |
| 5 | |
| 6 | A WebService has a collection of Route objects that dispatch incoming Http Requests to a function calls. |
| 7 | Typically, a WebService has a root path (e.g. /users) and defines common MIME types for its routes. |
| 8 | WebServices must be added to a container (see below) in order to handler Http requests from a server. |
| 9 | |
| 10 | A Route is defined by a HTTP method, an URL path and (optionally) the MIME types it consumes (Content-Type) and produces (Accept). |
| 11 | This package has the logic to find the best matching Route and if found, call its Function. |
| 12 | |
| 13 | ws := new(restful.WebService) |
| 14 | ws. |
| 15 | Path("/users"). |
| 16 | Consumes(restful.MIME_JSON, restful.MIME_XML). |
| 17 | Produces(restful.MIME_JSON, restful.MIME_XML) |
| 18 | |
| 19 | ws.Route(ws.GET("/{user-id}").To(u.findUser)) // u is a UserResource |
| 20 | |
| 21 | ... |
| 22 | |
| 23 | // GET http://localhost:8080/users/1 |
| 24 | func (u UserResource) findUser(request *restful.Request, response *restful.Response) { |
| 25 | id := request.PathParameter("user-id") |
| 26 | ... |
| 27 | } |
| 28 | |
| 29 | The (*Request, *Response) arguments provide functions for reading information from the request and writing information back to the response. |
| 30 | |
| 31 | See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-user-resource.go with a full implementation. |
| 32 | |
| 33 | Regular expression matching Routes |
| 34 | |
| 35 | A Route parameter can be specified using the format "uri/{var[:regexp]}" or the special version "uri/{var:*}" for matching the tail of the path. |
| 36 | For example, /persons/{name:[A-Z][A-Z]} can be used to restrict values for the parameter "name" to only contain capital alphabetic characters. |
| 37 | Regular expressions must use the standard Go syntax as described in the regexp package. (https://code.google.com/p/re2/wiki/Syntax) |
| 38 | This feature requires the use of a CurlyRouter. |
| 39 | |
| 40 | Containers |
| 41 | |
| 42 | A Container holds a collection of WebServices, Filters and a http.ServeMux for multiplexing http requests. |
| 43 | Using the statements "restful.Add(...) and restful.Filter(...)" will register WebServices and Filters to the Default Container. |
| 44 | The Default container of go-restful uses the http.DefaultServeMux. |
| 45 | You can create your own Container and create a new http.Server for that particular container. |
| 46 | |
| 47 | container := restful.NewContainer() |
| 48 | server := &http.Server{Addr: ":8081", Handler: container} |
| 49 | |
| 50 | Filters |
| 51 | |
| 52 | A filter dynamically intercepts requests and responses to transform or use the information contained in the requests or responses. |
| 53 | You can use filters to perform generic logging, measurement, authentication, redirect, set response headers etc. |
| 54 | In the restful package there are three hooks into the request,response flow where filters can be added. |
| 55 | Each filter must define a FilterFunction: |
| 56 | |
| 57 | func (req *restful.Request, resp *restful.Response, chain *restful.FilterChain) |
| 58 | |
| 59 | Use the following statement to pass the request,response pair to the next filter or RouteFunction |
| 60 | |
| 61 | chain.ProcessFilter(req, resp) |
| 62 | |
| 63 | Container Filters |
| 64 | |
| 65 | These are processed before any registered WebService. |
| 66 | |
| 67 | // install a (global) filter for the default container (processed before any webservice) |
| 68 | restful.Filter(globalLogging) |
| 69 | |
| 70 | WebService Filters |
| 71 | |
| 72 | These are processed before any Route of a WebService. |
| 73 | |
| 74 | // install a webservice filter (processed before any route) |
| 75 | ws.Filter(webserviceLogging).Filter(measureTime) |
| 76 | |
| 77 | |
| 78 | Route Filters |
| 79 | |
| 80 | These are processed before calling the function associated with the Route. |
| 81 | |
| 82 | // install 2 chained route filters (processed before calling findUser) |
| 83 | ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser)) |
| 84 | |
| 85 | See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go with full implementations. |
| 86 | |
| 87 | Response Encoding |
| 88 | |
| 89 | Two encodings are supported: gzip and deflate. To enable this for all responses: |
| 90 | |
| 91 | restful.DefaultContainer.EnableContentEncoding(true) |
| 92 | |
| 93 | If a Http request includes the Accept-Encoding header then the response content will be compressed using the specified encoding. |
| 94 | Alternatively, you can create a Filter that performs the encoding and install it per WebService or Route. |
| 95 | |
| 96 | See the example https://github.com/emicklei/go-restful/blob/master/examples/restful-encoding-filter.go |
| 97 | |
| 98 | OPTIONS support |
| 99 | |
| 100 | By installing a pre-defined container filter, your Webservice(s) can respond to the OPTIONS Http request. |
| 101 | |
| 102 | Filter(OPTIONSFilter()) |
| 103 | |
| 104 | CORS |
| 105 | |
| 106 | By installing the filter of a CrossOriginResourceSharing (CORS), your WebService(s) can handle CORS requests. |
| 107 | |
| 108 | cors := CrossOriginResourceSharing{ExposeHeaders: []string{"X-My-Header"}, CookiesAllowed: false, Container: DefaultContainer} |
| 109 | Filter(cors.Filter) |
| 110 | |
| 111 | Error Handling |
| 112 | |
| 113 | Unexpected things happen. If a request cannot be processed because of a failure, your service needs to tell via the response what happened and why. |
| 114 | For this reason HTTP status codes exist and it is important to use the correct code in every exceptional situation. |
| 115 | |
| 116 | 400: Bad Request |
| 117 | |
| 118 | If path or query parameters are not valid (content or type) then use http.StatusBadRequest. |
| 119 | |
| 120 | 404: Not Found |
| 121 | |
| 122 | Despite a valid URI, the resource requested may not be available |
| 123 | |
| 124 | 500: Internal Server Error |
| 125 | |
| 126 | If the application logic could not process the request (or write the response) then use http.StatusInternalServerError. |
| 127 | |
| 128 | 405: Method Not Allowed |
| 129 | |
| 130 | The request has a valid URL but the method (GET,PUT,POST,...) is not allowed. |
| 131 | |
| 132 | 406: Not Acceptable |
| 133 | |
| 134 | The request does not have or has an unknown Accept Header set for this operation. |
| 135 | |
| 136 | 415: Unsupported Media Type |
| 137 | |
| 138 | The request does not have or has an unknown Content-Type Header set for this operation. |
| 139 | |
| 140 | ServiceError |
| 141 | |
| 142 | In addition to setting the correct (error) Http status code, you can choose to write a ServiceError message on the response. |
| 143 | |
| 144 | Performance options |
| 145 | |
| 146 | This package has several options that affect the performance of your service. It is important to understand them and how you can change it. |
| 147 | |
| 148 | restful.DefaultContainer.DoNotRecover(false) |
| 149 | |
| 150 | DoNotRecover controls whether panics will be caught to return HTTP 500. |
| 151 | If set to false, the container will recover from panics. |
| 152 | Default value is true |
| 153 | |
| 154 | restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20)) |
| 155 | |
| 156 | If content encoding is enabled then the default strategy for getting new gzip/zlib writers and readers is to use a sync.Pool. |
| 157 | Because writers are expensive structures, performance is even more improved when using a preloaded cache. You can also inject your own implementation. |
| 158 | |
| 159 | Trouble shooting |
| 160 | |
| 161 | This package has the means to produce detail logging of the complete Http request matching process and filter invocation. |
| 162 | Enabling this feature requires you to set an implementation of restful.StdLogger (e.g. log.Logger) instance such as: |
| 163 | |
| 164 | restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile)) |
| 165 | |
| 166 | Logging |
| 167 | |
| 168 | The restful.SetLogger() method allows you to override the logger used by the package. By default restful |
| 169 | uses the standard library `log` package and logs to stdout. Different logging packages are supported as |
| 170 | long as they conform to `StdLogger` interface defined in the `log` sub-package, writing an adapter for your |
| 171 | preferred package is simple. |
| 172 | |
| 173 | Resources |
| 174 | |
| 175 | [project]: https://github.com/emicklei/go-restful |
| 176 | |
| 177 | [examples]: https://github.com/emicklei/go-restful/blob/master/examples |
| 178 | |
| 179 | [design]: http://ernestmicklei.com/2012/11/11/go-restful-api-design/ |
| 180 | |
| 181 | [showcases]: https://github.com/emicklei/mora, https://github.com/emicklei/landskape |
| 182 | |
| 183 | (c) 2012-2015, http://ernestmicklei.com. MIT License |
| 184 | */ |
| 185 | package restful |