9 "github.com/emicklei/go-restful/log"
12 // Copyright 2013 Ernest Micklei. All rights reserved.
13 // Use of this source code is governed by a license
14 // that can be found in the LICENSE file.
16 // WebService holds a collection of Route values that bind a Http Method + URL Path to a function.
17 type WebService struct {
19 pathExpr *pathExpression // cached compilation of rootPath as RegExp
23 pathParameters []*Parameter
24 filters []FilterFunction
28 typeNameHandleFunc TypeNameHandleFunction
32 // protects 'routes' if dynamic routes are enabled
33 routesLock sync.RWMutex
36 func (w *WebService) SetDynamicRoutes(enable bool) {
37 w.dynamicRoutes = enable
40 // TypeNameHandleFunction declares functions that can handle translating the name of a sample object
41 // into the restful documentation for the service.
42 type TypeNameHandleFunction func(sample interface{}) string
44 // TypeNameHandler sets the function that will convert types to strings in the parameter
45 // and model definitions. If not set, the web service will invoke
46 // reflect.TypeOf(object).String().
47 func (w *WebService) TypeNameHandler(handler TypeNameHandleFunction) *WebService {
48 w.typeNameHandleFunc = handler
52 // reflectTypeName is the default TypeNameHandleFunction and for a given object
53 // returns the name that Go identifies it with (e.g. "string" or "v1.Object") via
54 // the reflection API.
55 func reflectTypeName(sample interface{}) string {
56 return reflect.TypeOf(sample).String()
59 // compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it.
60 func (w *WebService) compilePathExpression() {
61 compiled, err := newPathExpression(w.rootPath)
63 log.Printf("invalid path:%s because:%v", w.rootPath, err)
69 // ApiVersion sets the API version for documentation purposes.
70 func (w *WebService) ApiVersion(apiVersion string) *WebService {
71 w.apiVersion = apiVersion
75 // Version returns the API version for documentation purposes.
76 func (w *WebService) Version() string { return w.apiVersion }
78 // Path specifies the root URL template path of the WebService.
79 // All Routes will be relative to this path.
80 func (w *WebService) Path(root string) *WebService {
82 if len(w.rootPath) == 0 {
85 w.compilePathExpression()
89 // Param adds a PathParameter to document parameters used in the root path.
90 func (w *WebService) Param(parameter *Parameter) *WebService {
91 if w.pathParameters == nil {
92 w.pathParameters = []*Parameter{}
94 w.pathParameters = append(w.pathParameters, parameter)
98 // PathParameter creates a new Parameter of kind Path for documentation purposes.
99 // It is initialized as required with string as its DataType.
100 func (w *WebService) PathParameter(name, description string) *Parameter {
101 return PathParameter(name, description)
104 // PathParameter creates a new Parameter of kind Path for documentation purposes.
105 // It is initialized as required with string as its DataType.
106 func PathParameter(name, description string) *Parameter {
107 p := &Parameter{&ParameterData{Name: name, Description: description, Required: true, DataType: "string"}}
112 // QueryParameter creates a new Parameter of kind Query for documentation purposes.
113 // It is initialized as not required with string as its DataType.
114 func (w *WebService) QueryParameter(name, description string) *Parameter {
115 return QueryParameter(name, description)
118 // QueryParameter creates a new Parameter of kind Query for documentation purposes.
119 // It is initialized as not required with string as its DataType.
120 func QueryParameter(name, description string) *Parameter {
121 p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string", CollectionFormat: CollectionFormatCSV.String()}}
126 // BodyParameter creates a new Parameter of kind Body for documentation purposes.
127 // It is initialized as required without a DataType.
128 func (w *WebService) BodyParameter(name, description string) *Parameter {
129 return BodyParameter(name, description)
132 // BodyParameter creates a new Parameter of kind Body for documentation purposes.
133 // It is initialized as required without a DataType.
134 func BodyParameter(name, description string) *Parameter {
135 p := &Parameter{&ParameterData{Name: name, Description: description, Required: true}}
140 // HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes.
141 // It is initialized as not required with string as its DataType.
142 func (w *WebService) HeaderParameter(name, description string) *Parameter {
143 return HeaderParameter(name, description)
146 // HeaderParameter creates a new Parameter of kind (Http) Header for documentation purposes.
147 // It is initialized as not required with string as its DataType.
148 func HeaderParameter(name, description string) *Parameter {
149 p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
154 // FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes.
155 // It is initialized as required with string as its DataType.
156 func (w *WebService) FormParameter(name, description string) *Parameter {
157 return FormParameter(name, description)
160 // FormParameter creates a new Parameter of kind Form (using application/x-www-form-urlencoded) for documentation purposes.
161 // It is initialized as required with string as its DataType.
162 func FormParameter(name, description string) *Parameter {
163 p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
168 // Route creates a new Route using the RouteBuilder and add to the ordered list of Routes.
169 func (w *WebService) Route(builder *RouteBuilder) *WebService {
171 defer w.routesLock.Unlock()
172 builder.copyDefaults(w.produces, w.consumes)
173 w.routes = append(w.routes, builder.Build())
177 // RemoveRoute removes the specified route, looks for something that matches 'path' and 'method'
178 func (w *WebService) RemoveRoute(path, method string) error {
179 if !w.dynamicRoutes {
180 return errors.New("dynamic routes are not enabled.")
183 defer w.routesLock.Unlock()
184 newRoutes := make([]Route, (len(w.routes) - 1))
186 for ix := range w.routes {
187 if w.routes[ix].Method == method && w.routes[ix].Path == path {
190 newRoutes[current] = w.routes[ix]
191 current = current + 1
197 // Method creates a new RouteBuilder and initialize its http method
198 func (w *WebService) Method(httpMethod string) *RouteBuilder {
199 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod)
202 // Produces specifies that this WebService can produce one or more MIME types.
203 // Http requests must have one of these values set for the Accept header.
204 func (w *WebService) Produces(contentTypes ...string) *WebService {
205 w.produces = contentTypes
209 // Consumes specifies that this WebService can consume one or more MIME types.
210 // Http requests must have one of these values set for the Content-Type header.
211 func (w *WebService) Consumes(accepts ...string) *WebService {
216 // Routes returns the Routes associated with this WebService
217 func (w *WebService) Routes() []Route {
218 if !w.dynamicRoutes {
221 // Make a copy of the array to prevent concurrency problems
223 defer w.routesLock.RUnlock()
224 result := make([]Route, len(w.routes))
225 for ix := range w.routes {
226 result[ix] = w.routes[ix]
231 // RootPath returns the RootPath associated with this WebService. Default "/"
232 func (w *WebService) RootPath() string {
236 // PathParameters return the path parameter names for (shared among its Routes)
237 func (w *WebService) PathParameters() []*Parameter {
238 return w.pathParameters
241 // Filter adds a filter function to the chain of filters applicable to all its Routes
242 func (w *WebService) Filter(filter FilterFunction) *WebService {
243 w.filters = append(w.filters, filter)
247 // Doc is used to set the documentation of this service.
248 func (w *WebService) Doc(plainText string) *WebService {
249 w.documentation = plainText
253 // Documentation returns it.
254 func (w *WebService) Documentation() string {
255 return w.documentation
262 // HEAD is a shortcut for .Method("HEAD").Path(subPath)
263 func (w *WebService) HEAD(subPath string) *RouteBuilder {
264 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath)
267 // GET is a shortcut for .Method("GET").Path(subPath)
268 func (w *WebService) GET(subPath string) *RouteBuilder {
269 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath)
272 // POST is a shortcut for .Method("POST").Path(subPath)
273 func (w *WebService) POST(subPath string) *RouteBuilder {
274 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath)
277 // PUT is a shortcut for .Method("PUT").Path(subPath)
278 func (w *WebService) PUT(subPath string) *RouteBuilder {
279 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath)
282 // PATCH is a shortcut for .Method("PATCH").Path(subPath)
283 func (w *WebService) PATCH(subPath string) *RouteBuilder {
284 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath)
287 // DELETE is a shortcut for .Method("DELETE").Path(subPath)
288 func (w *WebService) DELETE(subPath string) *RouteBuilder {
289 return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath)