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