yolk / valvat

Validates european vat numbers. Standalone or as a ActiveModel validator.
MIT License
318 stars 80 forks source link

Add caching #118

Open nicolas-brousse opened 1 year ago

nicolas-brousse commented 1 year ago

Hi!

We currently have some issues with usage of VIES API on one of our project because of their API have some issues. It's not related to valvat gem which does its work correctly. But I was thinking of having some little cache to avoid calling too many time VIES API when not required.

Since VAT validity does not change this often, I guess 1 or few hour of cache on a VAT number may not be risky.

I will take time to do a pull request, but I prefer to discuss here before doing some code.

One thing to have in mind is that this gem is not fully related to Rails and should work without it. So Valvat::Lookup objects may not be able to use Rails.cache (at least directly).

So I've thing about 2 ways of doing caching:

  1. On lookup Having a generic cache object (ex: https://github.com/alexreisner/geocoder#caching) that could be use as proxy for Rails.cache.
  2. On validation only Add a cache: true (or cache: 2.hours) option in validator that may use Rails.cache.

What do you think about it?

crysper commented 1 year ago

I think that's a great feature to have. We got tons for rate limit errors from them. Not related to this gem, any of you found a better service to validate VAT? we get daily rate limit errors and server down errors.... it's extremely unreliable.

yolk commented 1 year ago

@nicolas-brousse A caching option for VAT lookups with the caching option behind a proxy ala geocoder seems to be reasonable. I feel a slight hesitation for it, because strictly speaking it wouldn't be legally compliant to re-play the results of lookups. So I would prefer to choose the caching per lookup and default to direct lookups, so the behavior is transparent at least.

But why would you like to cache the local validation? Or is there some misunderstanding?

ksol commented 1 year ago

It depends on your use-case, but on our side we validate a VAT number only when it changes (not on every model save), and we save when was the last lookup performed in db. This way, we avoid double-checks and we can re-check periodically for old numbers.

Even with a cache, you may end up getting rate-limit issues with some countries webservices if you have enough traffic, a lot of objects to backfill, etc

Were it up to me, I'd add the ability to the lib to automatically save "last lookup performed at" (we currently use a callback that updates a timestamp column if vat_number_changed?), and give examples related to:

  1. performing a lookup only when the relevant underlying data changes (vat_number, country of the entity)
  2. building a routine to redo a lookup after a certain duration
yolk commented 1 year ago

@ksol It seems to me both of your examples are too specific and therefor would be out of the scope for this gem. It wouldn't make sense for me to abstract the required storage and background processing capabilities. This also violates rules in some member states regarding checking the VAT id every time before invoice creation.

But: A simple caching solution – for short periods – when performing a lookup call would still be "nice to have".