github.com/mailgun/mailgun-go/v3@v3.6.4/routes.go (about) 1 package mailgun 2 3 import ( 4 "context" 5 "strconv" 6 ) 7 8 // A Route structure contains information on a configured or to-be-configured route. 9 // When creating a new route, the SDK only uses a subset of the fields of this structure. 10 // In particular, CreatedAt and ID are meaningless in this context, and will be ignored. 11 // Only Priority, Description, Expression, and Actions need be provided. 12 type Route struct { 13 // The Priority field indicates how soon the route works relative to other configured routes. 14 // Routes of equal priority are consulted in chronological order. 15 Priority int `json:"priority,omitempty"` 16 // The Description field provides a human-readable description for the route. 17 // Mailgun ignores this field except to provide the description when viewing the Mailgun web control panel. 18 Description string `json:"description,omitempty"` 19 // The Expression field lets you specify a pattern to match incoming messages against. 20 Expression string `json:"expression,omitempty"` 21 // The Actions field contains strings specifying what to do 22 // with any message which matches the provided expression. 23 Actions []string `json:"actions,omitempty"` 24 25 // The CreatedAt field provides a time-stamp for when the route came into existence. 26 CreatedAt RFC2822Time `json:"created_at,omitempty"` 27 // ID field provides a unique identifier for this route. 28 Id string `json:"id,omitempty"` 29 } 30 31 type routesListResponse struct { 32 // is -1 if Next() or First() have not been called 33 TotalCount int `json:"total_count"` 34 Items []Route `json:"items"` 35 } 36 37 type createRouteResp struct { 38 Message string `json:"message"` 39 Route `json:"route"` 40 } 41 42 // ListRoutes allows you to iterate through a list of routes returned by the API 43 func (mg *MailgunImpl) ListRoutes(opts *ListOptions) *RoutesIterator { 44 var limit int 45 if opts != nil { 46 limit = opts.Limit 47 } 48 49 if limit == 0 { 50 limit = 100 51 } 52 53 return &RoutesIterator{ 54 mg: mg, 55 url: generatePublicApiUrl(mg, routesEndpoint), 56 routesListResponse: routesListResponse{TotalCount: -1}, 57 limit: limit, 58 } 59 } 60 61 type RoutesIterator struct { 62 routesListResponse 63 64 limit int 65 mg Mailgun 66 offset int 67 url string 68 err error 69 } 70 71 // If an error occurred during iteration `Err()` will return non nil 72 func (ri *RoutesIterator) Err() error { 73 return ri.err 74 } 75 76 // Offset returns the current offset of the iterator 77 func (ri *RoutesIterator) Offset() int { 78 return ri.offset 79 } 80 81 // Next retrieves the next page of items from the api. Returns false when there 82 // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve 83 // the error 84 func (ri *RoutesIterator) Next(ctx context.Context, items *[]Route) bool { 85 if ri.err != nil { 86 return false 87 } 88 89 ri.err = ri.fetch(ctx, ri.offset, ri.limit) 90 if ri.err != nil { 91 return false 92 } 93 94 cpy := make([]Route, len(ri.Items)) 95 copy(cpy, ri.Items) 96 *items = cpy 97 if len(ri.Items) == 0 { 98 return false 99 } 100 ri.offset = ri.offset + len(ri.Items) 101 return true 102 } 103 104 // First retrieves the first page of items from the api. Returns false if there 105 // was an error. It also sets the iterator object to the first page. 106 // Use `.Err()` to retrieve the error. 107 func (ri *RoutesIterator) First(ctx context.Context, items *[]Route) bool { 108 if ri.err != nil { 109 return false 110 } 111 ri.err = ri.fetch(ctx, 0, ri.limit) 112 if ri.err != nil { 113 return false 114 } 115 cpy := make([]Route, len(ri.Items)) 116 copy(cpy, ri.Items) 117 *items = cpy 118 ri.offset = len(ri.Items) 119 return true 120 } 121 122 // Last retrieves the last page of items from the api. 123 // Calling Last() is invalid unless you first call First() or Next() 124 // Returns false if there was an error. It also sets the iterator object 125 // to the last page. Use `.Err()` to retrieve the error. 126 func (ri *RoutesIterator) Last(ctx context.Context, items *[]Route) bool { 127 if ri.err != nil { 128 return false 129 } 130 131 if ri.TotalCount == -1 { 132 return false 133 } 134 135 ri.offset = ri.TotalCount - ri.limit 136 if ri.offset < 0 { 137 ri.offset = 0 138 } 139 140 ri.err = ri.fetch(ctx, ri.offset, ri.limit) 141 if ri.err != nil { 142 return false 143 } 144 cpy := make([]Route, len(ri.Items)) 145 copy(cpy, ri.Items) 146 *items = cpy 147 return true 148 } 149 150 // Previous retrieves the previous page of items from the api. Returns false when there 151 // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve 152 // the error if any 153 func (ri *RoutesIterator) Previous(ctx context.Context, items *[]Route) bool { 154 if ri.err != nil { 155 return false 156 } 157 158 if ri.TotalCount == -1 { 159 return false 160 } 161 162 ri.offset = ri.offset - (ri.limit * 2) 163 if ri.offset < 0 { 164 ri.offset = 0 165 } 166 167 ri.err = ri.fetch(ctx, ri.offset, ri.limit) 168 if ri.err != nil { 169 return false 170 } 171 cpy := make([]Route, len(ri.Items)) 172 copy(cpy, ri.Items) 173 *items = cpy 174 if len(ri.Items) == 0 { 175 return false 176 } 177 return true 178 } 179 180 func (ri *RoutesIterator) fetch(ctx context.Context, skip, limit int) error { 181 r := newHTTPRequest(ri.url) 182 r.setBasicAuth(basicAuthUser, ri.mg.APIKey()) 183 r.setClient(ri.mg.Client()) 184 185 if skip != 0 { 186 r.addParameter("skip", strconv.Itoa(skip)) 187 } 188 if limit != 0 { 189 r.addParameter("limit", strconv.Itoa(limit)) 190 } 191 192 return getResponseFromJSON(ctx, r, &ri.routesListResponse) 193 } 194 195 // CreateRoute installs a new route for your domain. 196 // The route structure you provide serves as a template, and 197 // only a subset of the fields influence the operation. 198 // See the Route structure definition for more details. 199 func (mg *MailgunImpl) CreateRoute(ctx context.Context, prototype Route) (_ignored Route, err error) { 200 r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint)) 201 r.setClient(mg.Client()) 202 r.setBasicAuth(basicAuthUser, mg.APIKey()) 203 p := newUrlEncodedPayload() 204 p.addValue("priority", strconv.Itoa(prototype.Priority)) 205 p.addValue("description", prototype.Description) 206 p.addValue("expression", prototype.Expression) 207 for _, action := range prototype.Actions { 208 p.addValue("action", action) 209 } 210 var resp createRouteResp 211 if err = postResponseFromJSON(ctx, r, p, &resp); err != nil { 212 return _ignored, err 213 } 214 return resp.Route, err 215 } 216 217 // DeleteRoute removes the specified route from your domain's configuration. 218 // To avoid ambiguity, Mailgun identifies the route by unique ID. 219 // See the Route structure definition and the Mailgun API documentation for more details. 220 func (mg *MailgunImpl) DeleteRoute(ctx context.Context, id string) error { 221 r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id) 222 r.setClient(mg.Client()) 223 r.setBasicAuth(basicAuthUser, mg.APIKey()) 224 _, err := makeDeleteRequest(ctx, r) 225 return err 226 } 227 228 // GetRoute retrieves the complete route definition associated with the unique route ID. 229 func (mg *MailgunImpl) GetRoute(ctx context.Context, id string) (Route, error) { 230 r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id) 231 r.setClient(mg.Client()) 232 r.setBasicAuth(basicAuthUser, mg.APIKey()) 233 var envelope struct { 234 Message string `json:"message"` 235 *Route `json:"route"` 236 } 237 err := getResponseFromJSON(ctx, r, &envelope) 238 if err != nil { 239 return Route{}, err 240 } 241 return *envelope.Route, err 242 243 } 244 245 // UpdateRoute provides an "in-place" update of the specified route. 246 // Only those route fields which are non-zero or non-empty are updated. 247 // All other fields remain as-is. 248 func (mg *MailgunImpl) UpdateRoute(ctx context.Context, id string, route Route) (Route, error) { 249 r := newHTTPRequest(generatePublicApiUrl(mg, routesEndpoint) + "/" + id) 250 r.setClient(mg.Client()) 251 r.setBasicAuth(basicAuthUser, mg.APIKey()) 252 p := newUrlEncodedPayload() 253 if route.Priority != 0 { 254 p.addValue("priority", strconv.Itoa(route.Priority)) 255 } 256 if route.Description != "" { 257 p.addValue("description", route.Description) 258 } 259 if route.Expression != "" { 260 p.addValue("expression", route.Expression) 261 } 262 if route.Actions != nil { 263 for _, action := range route.Actions { 264 p.addValue("action", action) 265 } 266 } 267 // For some reason, this API function just returns a bare Route on success. 268 // Unsure why this is the case; it seems like it ought to be a bug. 269 var envelope Route 270 err := putResponseFromJSON(ctx, r, p, &envelope) 271 return envelope, err 272 }