joraeuw
Hello everyone,
I have been working with Elixir for the past 3+ years and I think its about time I give something back to the community. I have been looking for a library that allows me to easily send push notifications to PWA, by abstracting myself from the RFC’s involved and the encryption logic but I didn’t find anything suitable so I decided to build one myself.
ExNudge is a pure elixir library that send push notifications to web clients (I use it for a PWA) using the protocol described under RFC 8291 and RFC 8292 (VAPID). I plan on expanding it a bit with for example retry system on failed requests and FCM/APNS specific implementation, but that all depends on wether or not its being useful to someone ![]()
Feel free to ask for features, fork and create a PR or an issue and tell me what you think, I would love to get some feedback both on the ease of use and code quality!
Thank you for your time :))
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 12 Posts
olivermt
Cool that you implemented for PWA!
Have you considered PR’ing that side to Pigeon — Pigeon v2.0.1 which is fully featured for the app native side of things?
joraeuw
Actually, no I didn’t think of that. I went over Pigeon when I was looking for a solution specifically for PWA and forgot about it.
In that case what is a better practice? Should I fork and add my implementation as a library to pigeon? To be honest though, I would rather have the separation. I wouldn’t want to install a library that supports native and web when in most cases, applications will use one of the two. So perhaps my plan on expanding with FCM/APNS is a bad idea after all, since there is a pretty good solution that does that.
One think that might be beneficial is implementing a conversion between structs in my library and Pigeon
tangui
Great, thanks for the contribution!
I have a few questions:
web_push_elixirandweb_push_elixir?waxthinking it was too complicated - it’s not. And not long ago I couldn’t usehttps://github.com/discord/manifoldin an Erlang project, had to rewrite it.)Cheers!
joraeuw
One of the considerations i had before building this library was web_push_elixir but I ran into some issues while using it. Unfortunately I don’t really remember what the issue was there (perhaps it was compatibility with Arc), but after going though the code I noticed some inconstancies with RFC 8292 . I haven’t compared the encryption and everything one-to-one but one major difference were the headers. The RFC describes the usage of the authorization header using the “vapid” key and “t=? k=?” as a value, whereas the library implemented something different, perhaps RFC 8291. I have also added minimal concurrency and telemetry. I also want to expand it a bit to allow at least retries of failed requests and callback functions. For example cleanup callback that removes certain subscriptions from the database when they expire and creates a new one in place, I can use rate limit with exponential backoff and fallback to email notification, perhaps if a message is too large a retry with shorter message can be useful and so on.
I never even thought of making it compatible with Erlang. I know I can “import” Erlang code into elixir but I had no idea the reverse was possible as well. I will take a look. Thank you for the suggestion!
I will take a look at the anti-pattern thing as well. What do you mean by wider community review? But yes, that is part of the point of this post. I want to understand where I’m lacking knowledge, wether or not my library makes sense for the community and get to know fellow elixir developers
Thank you for your time!
mayel
Thanks for making and sharing this! I had tried to implement webpush with GitHub - danhper/elixir-web-push-encryption: Elixir implementation of Web Push Payload encryption. · GitHub but hadn’t got it working… Will give ExNudge a try! Would you consider sharing an example app repo? That would be very helpful to better understand all the necessary parts. For example where do “client_public_key” and “client_auth_secret” with which you create the subscription come from?
joraeuw
Yeah sure! I will create a Phoenix example very soon. Perhaps by the end of tomorrow. The tokens come from PushManager. I will add a better explanation and a code example to clarify further.
christhekeele
Yup! In compiled BEAM files, including both Erlang and Elixir, module names are just atoms, and both can cross-call each other. Elixir’s namespaced
Module.Names are just fancy wrappers around compile-time verified andalias-friendly atoms.Elixir, designed after Erlang, has the luxury of making calling Erlang module cross-calls as elegant as
:module_name.function(). To do something similar from Erlang you have to deal with the more ungainly'Elixir.Module.Name':function()syntax. This is why Elixir libraries “supporting” Erlang better will often simplydefmodule Module.Nameand then implement adefmodule :module_namethatdefdelegatesto Elixir functions, to make it nicer to call from Erlang asmodule_name:function().I also think “Erlangifying” an Elixir library involves making it support rebar3 in practice, but I have no experience on this front.
tangui
Yeah, the JOSE library that you use does exactly that, you can take a look at the code. It’s way easier to use Erlang from Elixir, than the opposite. If you write the core in Erlang, you have the guarantee that someone somewhere in a basement some time in the future will be grateful
Other remarks:
HTTPoisonupon the user. An alternative is to useTeslaand let the user choose its favorite HTTP library (example). Another option is to write a behaviour for HTTP requesting and let the user implement its own (and / or provide with a default implementation securely using for instancehttpc). I’d normalize the success response as well, now it’s{:ok, %HTTPoison{}}but what if you change the library in the future? Does the response actually contains something useful?@moduledoc falseto prevent having them in the docExNudge.send_notifications/3ExNudge.generate_vapid_keys/0is used at config time. Maybe a Mix task would be more useful? I think other Web Push libraries do that{:error, Exception.t()}form: exception are better documented (example), can have a default error message, additional information and in case you don’t know what to do with them you can just throw (raise) them awayCheers!
joraeuw
Sorry for misleading you @mayel Its been busy at work so I will have to do it in the weekend.
joraeuw
Wow thank you guys for the great feedback. I will take a look and improve the library as per your suggestions!