Until now, we have conveniently ignored the question of how to handle exceptions. What happens if our POST to the back end results in a 400-class error? How can we design Hipster MVC so that developers can handle exceptions appropriately?
Had we stuck with options, the answer would have been to add yet another callback inside the Map of options. Luckily for us, Completer and Future have a formal mechanism for dealing with just such a situation. A Completer invokes completeError to signal a problem and Future deals with problems with handleException to do something with that exception.
The default data sync behavior in HipsterSync would signal an exceptional condition to the future by calling completeError when the request status is not okay (for example, greater than 299).
| class HipsterSync { |
| // ... |
| static Future _defaultSync(method, model) { |
| var request = new HttpRequest(), |
| completer = new Completer(); |
| request. |
| onLoad. |
| listen((event) { |
| var req = event.target; |
| if (req.status > 299) { |
| completer. |
| completeError("That ain't gonna work: ${req.status}"); |
| } |
| |
| else { |
| var json = JSON.decode(req.responseText); |
| completer.complete(json); |
| } |
| }); |
| // Open and send the request |
| return completer.future; |
| } |
| } |
The value in completeError does not have to be a subclass of Exception—any old object will do. In this case, we supply a simple string.
| if (req.status > 299) { |
| completer. |
| completeError("That ain't gonna work: ${req.status}"); |
| } |
Back in the model class, we need to handle this exceptional case. The then method returns void, so it is not chainable. This requires us to store the after-send Future back in HipsterModel.save() in a local variable. We can then inject a happy-path then behavior into the Future along with handleException behavior.
| class HipsterModel { |
| // ... |
| Future<HipsterModel> save() { |
| Completer completer = new Completer(); |
| Future after_send = HipsterSync.send('post', this); |
| |
| after_send. |
| then((attrs) { /* ... */ }); |
| |
| after_send. |
| handleException((e) { /* ... */ }); |
| return completer.future; |
| } |
| } |
Since HipsterModel#save() is itself a Future, it should handle exceptions with a completeError of its own.
| after_send. |
| handleException((e) { |
| completer.completeError(e); |
| return true; |
| }); |
3.149.27.72