github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/doc.go (about)

     1  /*
     2  	Adding a Route
     3  
     4  	Adding a new route to the REST v2 API requires creation of a few structs and
     5  	implementation of a few new methods.
     6  
     7  	RequestHandler
     8  
     9  	The RequestHandler is a central interface in the REST v2 API with following
    10  	signature:
    11  
    12  					type RequestHandler interface {
    13  						Handler() RequestHandler
    14  						ParseAndValidate(*http.Request) error
    15  						Execute(servicecontext.ServiceContext) (ResponseData, error)
    16  					}
    17  
    18  	RequestHandlers should be placed in files in the route/ directory depending on the type
    19  	of resource they access.
    20  
    21  	To add a new route you must create a struct that implements its three main interface
    22  	methods. The Handler method must return a new copy of the RequestHandler so that
    23  	a new copy of this object can be used on successive calls to the same endpoint.
    24  
    25  	The ParseAndValidate method is the only method that has access to the http.Request object.
    26  	All necessary query parameters and request body information must be fetched from the request
    27  	in this function and added to the struct for use in the Execute function. These fetches can
    28  	take a few main forms:
    29  
    30  	From mux Context
    31  
    32  	Data gathered before the main request by the PrefetchFunc's are attached to the
    33  	mux Context for that request and can be fetched using the context.Get function
    34  	and providing it with the correct key for the desired data.
    35  
    36  	From the Route Variables
    37  
    38  	Variables from routes defined with variables such as /tasks/{task_id} can be
    39  	fetched using calls to the mux.Vars function and providing the variable name
    40  	to the returned map. For example, the taskId of that route could be fetched using:
    41  
    42  					mux.Vars(r)["task_id"]
    43  
    44  	From the URL Query Parameters
    45  
    46  	To fetch variables from the URL query parameters, get it from the http.Request's
    47  	URL object using:
    48  
    49  					r.URL.Query().Get("status")
    50  
    51  	Finally, the Execute method is the only method with access to the ServiceContext
    52  	and is therefore capable of making calls to the backing database to fetch and alter
    53  	its state. The Execute method should use the parameters gathered in the ParseAndValidate
    54  	method to implement the main logic and functionality of the request.
    55  
    56  	Pagination
    57  
    58  	PaginationExecutor is a struct that already implements the RequestHandler interface.
    59  	To create a method with pagination, the only function that is needed is a PaginatorFunc.
    60  
    61  	PaginatorFunc
    62  
    63  	A PaginatorFunc defines how to paginate over a resource given a key to start pagination
    64  	from and a limit to limit the number of results. PaginatorFunc has the following signature:
    65  
    66  					func(key string, limit int, args interface{}, sc ServiceContext)([]Model, *PageResult, error)
    67  
    68  	The key and limit are fetched automatically by the PaginationExecutor's ParseAndValidate
    69  	function. These parameters should be used to query for the correct set of results.
    70  
    71  	The args is a parameter that may optionally be used when more information is
    72  	needed to completed the request. To populate this field, the RequestHandler that
    73  	wraps the PaginationExecutor must implement a ParseAndValidate method that overwrites
    74  	the PaginationExecutor's and then calls it with the resulting request for example,
    75  	a RequestHandler called fooRequestHandler that needs additional args would look
    76  	like:
    77  
    78  					fooRequestHandler{
    79  					 *PaginationExecutor
    80  					}
    81  
    82  					extraFooArgs{
    83  						extraParam string
    84  					}
    85  
    86  					func(f *fooRequesetHandler) ParseAndValidate(r *http.RequestHandler) error{
    87  						urlParam := r.URL.Query().Get("extra_url_param")
    88  						f.PaginationExecutor.Args = extraFooArgs{urlParam}
    89  
    90  						return f.PaginationExecutor.ParseAndValidate(r)
    91  					}
    92  
    93  					func fooRequestPaginator(key string, limit int, args interface{},
    94  						 sc servicecontext.ServiceContext)([]model.Model, *PageResult, error){
    95  
    96  						 fooArgs, ok := args.(extraFooArgs)
    97  						 if !ok {
    98  							// Error
    99  						 }
   100  
   101  					...
   102  					}
   103  
   104  
   105  	PageResult
   106  
   107  	The PageResult is a struct that must be constructed and returned by a PaginatorFunc
   108  	It contains the information used for creating links to the next and previous page of
   109  	results.
   110  
   111  	To construct a Page, you must provide it with the limit of the number of results
   112  	for the page, which is either the default limit if none was provided, the limit
   113  	of the previous request if provided, or the number of documents between the page
   114  	and the end of the result set. The end of the result set is either the beginning of
   115  	set of results currently being returned if constructing a previous page, or the end
   116  	of all results if constructing a next page.
   117  
   118  	The Page must also contain the key of the item that begins the Page of results.
   119  	For example, when creating a next Page when fetching a page of 100 tasks, the
   120  	task_id of the 101st task should be used as the key for the next Page.
   121  
   122  	If the page being returned is the first or last page of pagination, then there
   123  	is no need to create that Page.
   124  
   125  	MethodHandler
   126  
   127  	The MethodHandler type contains all data and types for complete execution of an
   128  	API method. It holds:
   129  
   130  	- A list of PrefetchFuncs used for grabbing data needed before
   131  	the main execution of a method, such as user data for authentication
   132  
   133  	- The HTTP method type (GET, PUT, etc.)
   134  
   135  	- The Authenticator this method uses to control access to its data
   136  
   137  	- The RequestHandler this method uses for the main execution of its request
   138  
   139  	A MethodHandler is a composition of defined structs and functions that in total
   140  	comprise the method. Many Authenticator and PrefetchFunc are already implemented
   141  	and only need to be attached to this object to create the method once the Requesthandler
   142  	is complete.
   143  
   144  	RouteManager
   145  
   146  	The RouteManager type holds all of the methods associated with a particular API
   147  	route. It holds these as an array of MethodHandlers. It also contains the path
   148  	by which this route may be accessed, and the version of the API that this is
   149  	implemented as part of.
   150  
   151  	When adding to the API there may already be a RouteManger in existence for the
   152  	method being devloped. For example, if a method for GET /tasks/<task_id> is
   153  	already implemented, then a new route manager is not required when createing POST /tasks/<task_id>.
   154  	Its implementation only needs to be added to the existing RouteManager.
   155  
   156  	Once created, the RouteManager must be registered onto the mux.Router with the
   157  	ServiceContext by calling
   158  
   159  	     route.Register(router, serviceContext).
   160  */
   161  package route