exBankID - A simple abstraction over the swedish BankID api

I just released a super simple client for the Swedish BankID API.
https://hex.pm/packages/exBankID

Not all that much to say about it, just hoping it can be useful to someone!

If you like it tell a friend and put a star on the github repo
If you don’t like it all feedback is more than welcome!
Thanks!

11 Likes

Nice :fire:

Thanks!

Good work!

Suggestion for improvement - make the http client and json parser pluggable.

Thanks for the suggestions!
I will most definitely put this on the road-map.
I have been looking a bit at how ecto does this with adapters. Do you have any other ideas on how to achieve this?

I’ve never built it myself in Elixir, but you can look at other libs for inspiration. Look how ex_aws does it with json https://github.com/ex-aws/ex_aws#json-codec-configuration

Maybe @benwilson512 could give some tips how to structure such a pluggable library. He mentioned some ideas in the ExAws thread. I would love a discussion about a a good architecture for a library :slight_smile:

2 Likes

While I am not a specialist here, I have similar constraints for a project I’m working on, and I think the best path forward is to define a behaviour for the http calls and the json parsing, then it’s just a matter of implementing the callbacks for whatever library.
\Edit
You can then call functions from modules implementing the behaviour having said module declared eg in app env.
Benefits are : users can implement their own modules with libraries you didn’t think of at first and you can mock with mox.

3 Likes

Thank you!

Yes using a behaviour would be the most obvious way to introduce a safe level of indirection/decoupling.
This would be akin to depending on an interface in the OOP world?

The only real question is where the selection of the implementation should be done.

  1. Using the app env seems straightforward, but it would have some drawbacks.
  2. Passing a module atom in a Keyword list to all functions in ExBankID should be doable. But this would clutter up the library API.
  3. Maybe a combination one and two.

Thanks for the link! And I will definitely take a look at the ExAws thread.
If you haven’t, take a look at my reply to krstfk. I would like to hear your thoughts, as well!

Look how ExAws does it.

Behavior: https://github.com/ex-aws/ex_aws/blob/master/lib/ex_aws/request/http_client.ex

This is how we implement it in our project (using Mojito instead of the default client):

defmodule DB.S3.HttpClient do
  @moduledoc false
  @behaviour ExAws.Request.HttpClient
  def request(method, url, body, headers, http_opts \\ []) do
    case Mojito.request(method, url, headers, body, http_opts) do
      {:ok, response} -> {:ok, response}
      {:error, error} -> {:error, %{reason: error}}
    end
  end
end

The implementation module is passed through config. And used in ExAws like this: https://github.com/ex-aws/ex_aws/blob/master/lib/ex_aws/request.ex#L42

And I think that such a config is perfectly fine for Json and HttpClient. I don’t see any usecase where you would want to have 2 different parsers in the app, right?

3 Likes

You are probably right, but just like ExAws I will make all the config values overridable when invoking any of the functions in ExBankID. I have played a bit with NimbleOptions, maybe one way would be to have the schema default to whatever value is in the app env.

Anyhow thanks for all the great advice!

1 Like

Ah, I built something like this, specifically BankID, when building on a product that got cancelled. Your description of the library says stateless. But if I recall correctly there is supposed to be some polling while waiting for the user to do their thing. I don’t have time to dig through your code for how you handle that right now but it seems stateful by design to me. I recall it seemed to map well to a GenServer or so.

Let me know if you want to see what I did. I think I could just open it up for reference.

1 Like

Great question!
You are correct in that there is supposed to be some polling on the collect endpoint.

By design, this is not handled by this library at all.
The rationale behind this is that this library will be more useful to other developers if it doesn’t make any assumptions about what polling mechanism fits their use case.

However, I am planning on adding some functionality that would make implementing a polling mechanism almost trivial. First out will be to have ExBankID.collect be able to determine if the “BankID session” is in a collectable state. And then we will see where it goes from there.

Sure, it would be great to have a look at what you did!

1 Like

Should be open here now: https://github.com/lawik/elixir_bankid

I just used :httpc from Erlang for the HTTP client. I guess my design is pretty much the opposite where it all goes through a GenServer. Since you could easily implement what I’ve done as convenience options on top of your existing “simpler” design. Hope there is some interesting takeaways from what I did, I don’t remember how far I polished it :wink:

Might not have included a license, but feel free to grab whatever of course.

2 Likes

Just released v0.1.1 :fireworks:

New:

  • Http client is now pluggable
  • Validation and default values for opts in the ExBankId module, are now handled with NimbleOptions
  • :http_client, :url, :cert_file will now be loaded from the application environment if available.
  • The documentation is updated

Upcoming:

  • Pluggable JSON-encoder / decoder
  • Support for the requirement parameter when authenticating or signing
  • More comprehensive tests
  • Basic support for qr-codes
  • Client-side validation of personal numbers

Thanks to @egze, @krstfk, and @lawik for feedback and suggestions.

Find me on GitHub and Twitter

1 Like

Nice! Good work!

Noticed you have a typo in folder name: defalut.

Dangit!

Thanks for taking the time!

Found something else for you to optimize :slight_smile:

Maybe you can make the default http and json libs as a soft dependency.

Thanks! This is great stuff.
For a while, I was considering implementing the default http client with :httpc as a way of not forcing unnecessary external dependencies on the library users. But that would probably not be worth the effort.

Thinking about it, it makes complete sense that any pluggable dependencies should be soft dependencies.

keep 'em coming :upside_down_face:

1 Like

New release v0.2.0!

New:

  • Pluggable JSON-encoder / decoder.
  • Poison and HTTPoison are now optional deps.

Upcoming:

  • Support for the requirement parameter when authenticating or signing
  • More comprehensive tests
  • Basic support for qr-codes
  • Client-side validation of personal numbers

Thanks to @egze for helpful tips!

2 Likes