Rework WebPushService
Hi there again. I am proposing a few more relatively closely related changes to the API of the WebPushService class. Namely:
-
a7a8f08 which adds a
Notificationclass to hold all data for a web push notification along with aWebPushService.send(Notification)method. This reduces the amount of method parameters, simplifies the interface of theWebPushServiceclass, and allows passing around a web push notification as one coherent entity.
The multi-parametersendmethods are kept for now, but deprecated with a suggested replacement. The example in the README has been updated accordingly. -
7982c15 which turns
WebPushServiceinto an abstract class whichJdkHttpClientWebPushServiceinherits from as an implementation. Like this, code can be written against the interface ofWebPushServiceand the underlying implementation be swapped out, e.g., when a custom HTTP client should be used. This is also a step into the direction of #47 since the JDKHttpClient-related code is isolated. -
5d4f7e4 which changes the exception handling again because it turned out the
WebPushStatusExceptionwas still not enough for my use case (sorry for that) since I require access to the HTTP response headers as well (e.g.,Retry-Afterwhen an HTTP 429 response is returned), whichWebPush.getSubscriptionStatecannot provide.
The method was changed to throw the more genericWebPushExceptionagain andWebPushStatusExceptionwas removed. Instead, implementations ofWebPushServiceshould be able to throw their own exceptions inheriting fromWebPushExceptionwhich provide more context such as the concrete HTTP response object that caused the exception to be thrown. This new exception class would beJdkHttpClientWebPushService.WebPushHttpException.
Instead ofWebPushServiceimplementation-specific exception types theWebPushStatusExceptioncould be extended to include aresponse: Any? = nullfield, but that felt really unclean.
I realize that quite a bit of library code is touched by my changes, but it'd be great if you consider including them.
Hi @andreblanke, thank you very much for the work you invested in this. I don't have enough time to fully review this now, but some points that come to my mind instantly:
- This is really backwards incompatible change, so should probably wait for a new major version
- Can we do anything less breaking right now to saturate your use case?
- For what do you need those headers? Are they useful for other users of this lib?
- If so, should be integrate them in some kind of "response" from this library?
Thanks for your quick reply! It's understandable you can't immediately review all the changes.
This is really backwards incompatible change, so should probably wait for a new major version
I agree that a new major version would be appropriate. Although the only breaking change (leaving aside the deprecations) would be the instantiation of the WebPushService.
Before:
val webPushService: WebPushService = WebPushService(subject, vapidKeys)
After:
val webPushService: WebPushService = JdkHttpClientWebPushService(subject, vapidKeys)
It might also make sense to add a static factory method such as WebPushService.create instead of manually invoking a constructor.
Can we do anything less breaking right now to saturate your use case?
The simplest option would be to add the HTTP headers to the WebPushStatusException. My issue with that is that the exception might include even more fields in the future which would usually be contained in an HttpResponse object or similar.
Right now there's already the status code, the response body (only accessible when parsing the exception message), and then the headers which I'd like to access. Since the exception is thrown by getSubscriptionState, all that information must be passed to the method only for it to be possibly included in the exception.
Alternatively, the approach taken by 5d4f7e4 could be used standalone without separating the interface and implementation of WebPushService.
getSubscriptionState could throw a general WebPushException which is subsequently caught by WebPushService where a WebPushHttpException is thrown containing the HttpResponse. A remaining question would be how to deal with WebPushStatusException that now exists.
For what do you need those headers? Are they useful for other users of this lib?
I would like to back off from sending push notifications if the provider responds with an HTTP 429 Too Many Requests status which is usually accompanied by a Retry-After header containing either an amount of seconds to wait or a date-time.
If so, should be integrate them in some kind of "response" from this library?
I think it'd make sense to have this as functionality within the library itself, yes.