...

Source file src/github.com/emicklei/go-restful/v3/web_service.go

Documentation: github.com/emicklei/go-restful/v3

     1  package restful
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"reflect"
     7  	"sync"
     8  
     9  	"github.com/emicklei/go-restful/v3/log"
    10  )
    11  
    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.
    15  
    16  // WebService holds a collection of Route values that bind a Http Method + URL Path to a function.
    17  type WebService struct {
    18  	rootPath       string
    19  	pathExpr       *pathExpression // cached compilation of rootPath as RegExp
    20  	routes         []Route
    21  	produces       []string
    22  	consumes       []string
    23  	pathParameters []*Parameter
    24  	filters        []FilterFunction
    25  	documentation  string
    26  	apiVersion     string
    27  
    28  	typeNameHandleFunc TypeNameHandleFunction
    29  
    30  	dynamicRoutes bool
    31  
    32  	// protects 'routes' if dynamic routes are enabled
    33  	routesLock sync.RWMutex
    34  }
    35  
    36  func (w *WebService) SetDynamicRoutes(enable bool) {
    37  	w.dynamicRoutes = enable
    38  }
    39  
    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
    43  
    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
    49  	return w
    50  }
    51  
    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()
    57  }
    58  
    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)
    62  	if err != nil {
    63  		log.Printf("invalid path:%s because:%v", w.rootPath, err)
    64  		os.Exit(1)
    65  	}
    66  	w.pathExpr = compiled
    67  }
    68  
    69  // ApiVersion sets the API version for documentation purposes.
    70  func (w *WebService) ApiVersion(apiVersion string) *WebService {
    71  	w.apiVersion = apiVersion
    72  	return w
    73  }
    74  
    75  // Version returns the API version for documentation purposes.
    76  func (w *WebService) Version() string { return w.apiVersion }
    77  
    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 {
    81  	w.rootPath = root
    82  	if len(w.rootPath) == 0 {
    83  		w.rootPath = "/"
    84  	}
    85  	w.compilePathExpression()
    86  	return w
    87  }
    88  
    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{}
    93  	}
    94  	w.pathParameters = append(w.pathParameters, parameter)
    95  	return w
    96  }
    97  
    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)
   102  }
   103  
   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"}}
   108  	p.bePath()
   109  	return p
   110  }
   111  
   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)
   116  }
   117  
   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()}}
   122  	p.beQuery()
   123  	return p
   124  }
   125  
   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)
   130  }
   131  
   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}}
   136  	p.beBody()
   137  	return p
   138  }
   139  
   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)
   144  }
   145  
   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"}}
   150  	p.beHeader()
   151  	return p
   152  }
   153  
   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)
   158  }
   159  
   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"}}
   164  	p.beForm()
   165  	return p
   166  }
   167  
   168  // MultiPartFormParameter creates a new Parameter of kind Form (using multipart/form-data) for documentation purposes.
   169  // It is initialized as required with string as its DataType.
   170  func (w *WebService) MultiPartFormParameter(name, description string) *Parameter {
   171  	return MultiPartFormParameter(name, description)
   172  }
   173  
   174  func MultiPartFormParameter(name, description string) *Parameter {
   175  	p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
   176  	p.beMultiPartForm()
   177  	return p
   178  }
   179  
   180  // Route creates a new Route using the RouteBuilder and add to the ordered list of Routes.
   181  func (w *WebService) Route(builder *RouteBuilder) *WebService {
   182  	w.routesLock.Lock()
   183  	defer w.routesLock.Unlock()
   184  	builder.copyDefaults(w.produces, w.consumes)
   185  	w.routes = append(w.routes, builder.Build())
   186  	return w
   187  }
   188  
   189  // RemoveRoute removes the specified route, looks for something that matches 'path' and 'method'
   190  func (w *WebService) RemoveRoute(path, method string) error {
   191      if !w.dynamicRoutes {
   192          return errors.New("dynamic routes are not enabled.")
   193      }
   194      w.routesLock.Lock()
   195      defer w.routesLock.Unlock()
   196      newRoutes := []Route{}
   197      for _, route := range w.routes {
   198          if route.Method == method && route.Path == path {
   199              continue
   200          }
   201          newRoutes = append(newRoutes, route)
   202      }
   203      w.routes = newRoutes
   204      return nil
   205  }
   206  
   207  // Method creates a new RouteBuilder and initialize its http method
   208  func (w *WebService) Method(httpMethod string) *RouteBuilder {
   209  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod)
   210  }
   211  
   212  // Produces specifies that this WebService can produce one or more MIME types.
   213  // Http requests must have one of these values set for the Accept header.
   214  func (w *WebService) Produces(contentTypes ...string) *WebService {
   215  	w.produces = contentTypes
   216  	return w
   217  }
   218  
   219  // Consumes specifies that this WebService can consume one or more MIME types.
   220  // Http requests must have one of these values set for the Content-Type header.
   221  func (w *WebService) Consumes(accepts ...string) *WebService {
   222  	w.consumes = accepts
   223  	return w
   224  }
   225  
   226  // Routes returns the Routes associated with this WebService
   227  func (w *WebService) Routes() []Route {
   228  	if !w.dynamicRoutes {
   229  		return w.routes
   230  	}
   231  	// Make a copy of the array to prevent concurrency problems
   232  	w.routesLock.RLock()
   233  	defer w.routesLock.RUnlock()
   234  	result := make([]Route, len(w.routes))
   235  	for ix := range w.routes {
   236  		result[ix] = w.routes[ix]
   237  	}
   238  	return result
   239  }
   240  
   241  // RootPath returns the RootPath associated with this WebService. Default "/"
   242  func (w *WebService) RootPath() string {
   243  	return w.rootPath
   244  }
   245  
   246  // PathParameters return the path parameter names for (shared among its Routes)
   247  func (w *WebService) PathParameters() []*Parameter {
   248  	return w.pathParameters
   249  }
   250  
   251  // Filter adds a filter function to the chain of filters applicable to all its Routes
   252  func (w *WebService) Filter(filter FilterFunction) *WebService {
   253  	w.filters = append(w.filters, filter)
   254  	return w
   255  }
   256  
   257  // Doc is used to set the documentation of this service.
   258  func (w *WebService) Doc(plainText string) *WebService {
   259  	w.documentation = plainText
   260  	return w
   261  }
   262  
   263  // Documentation returns it.
   264  func (w *WebService) Documentation() string {
   265  	return w.documentation
   266  }
   267  
   268  /*
   269  	Convenience methods
   270  */
   271  
   272  // HEAD is a shortcut for .Method("HEAD").Path(subPath)
   273  func (w *WebService) HEAD(subPath string) *RouteBuilder {
   274  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath)
   275  }
   276  
   277  // GET is a shortcut for .Method("GET").Path(subPath)
   278  func (w *WebService) GET(subPath string) *RouteBuilder {
   279  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath)
   280  }
   281  
   282  // POST is a shortcut for .Method("POST").Path(subPath)
   283  func (w *WebService) POST(subPath string) *RouteBuilder {
   284  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath)
   285  }
   286  
   287  // PUT is a shortcut for .Method("PUT").Path(subPath)
   288  func (w *WebService) PUT(subPath string) *RouteBuilder {
   289  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath)
   290  }
   291  
   292  // PATCH is a shortcut for .Method("PATCH").Path(subPath)
   293  func (w *WebService) PATCH(subPath string) *RouteBuilder {
   294  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath)
   295  }
   296  
   297  // DELETE is a shortcut for .Method("DELETE").Path(subPath)
   298  func (w *WebService) DELETE(subPath string) *RouteBuilder {
   299  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath)
   300  }
   301  
   302  // OPTIONS is a shortcut for .Method("OPTIONS").Path(subPath)
   303  func (w *WebService) OPTIONS(subPath string) *RouteBuilder {
   304  	return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("OPTIONS").Path(subPath)
   305  }
   306  

View as plain text