joraeuw

joraeuw

ExNudge - Push Notification Library for Elixir

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 :slight_smile:

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 :))

Most Liked

joraeuw

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

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 and alias-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 simply defmodule Module.Name and then implement a defmodule :module_name that defdelegates to Elixir functions, to make it nicer to call from Erlang as module_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

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 :smile:

Other remarks:

  • you force the use of HTTPoison upon the user. An alternative is to use Tesla and 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 instance httpc). 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?
  • many modules seem to be for internal use - you can add @moduledoc false to prevent having them in the doc
  • I would have let the user handle batch sending notifications, as Elixir has all the needed primitives for that, and there might be other ways to do it (if you want “at least once” delivery then you’d probably use Oban). Thus I’d remove ExNudge.send_notifications/3
  • It seems to me ExNudge.generate_vapid_keys/0 is used at config time. Maybe a Mix task would be more useful? I think other Web Push libraries do that
  • I personnaly like when errors are returned in the {: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 away :smile:

Cheers!

tangui

tangui

Great, thanks for the contribution!

I have a few questions:

  • How does this library differ from web_push_elixir and web_push_elixir?
  • Have you considered making it compatible with Erlang for our Erlangist friends? Looks like it pretty low level, and I can see some needs to use it in Erlang directly. (I myself regret I didn’t do it for wax thinking it was too complicated - it’s not. And not long ago I couldn’t use https://github.com/discord/manifold in an Erlang project, had to rewrite it.)
  • I see this library uses application configuration, which is a anti-pattern. You might be interested in reading this page. You might be interested in a wider community review?

Cheers!

joraeuw

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 :smiley:

Thank you for your time!

Where Next?

Popular in Libraries Top

hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
OvermindDL1
Been making an MLElixir thing (not released yet…) for fun in spare time in the past day. I’m just trying to see how much I can get an ML...
132 13487 106
New
cjen07
parameterized pipe in elixir: |n> edit: negative index in |n> and mixed usage with |> are supported example: use ParamP...
New
wfgilman
I’ve cleaned up and open sourced three financial libraries I was using for my company. They are bindings for the APIs of these three comp...
New
tmbb
I’ve published the first version of my Makeup library. It’s a syntax highlighter for Elixir in the spirit of Pygments, Currently it highl...
New
mbuhot
EctoJob A transactional job queue built with Ecto, PostgreSQL and GenStage Available on Hex.pm: ecto_job | Hex Docs: API Reference — ec...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
ostinelli
Let’s write a database! Well not really, but I think it’s a little sad that there doesn’t seem to be a simple in-memory distributed KV da...
New

Other popular topics Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

Sub Categories:

We're in Beta

About us Mission Statement