Repository: svix/svix-webhooks (language: rust)

Issue:
Remove Ruby gem hard-dependency on typhoeus
## Feature Request

### Motivation

I'd be happy to use this gem to verify the webhook code, but I don't want to install typhoeus, which isn't needed for it. So, until it's removed, I'll probably just write the HMAC etc code myself.

### Proposal

MVP: make typhoeus a soft requirement for use in the api client, but not for installation. 

### Alternatives

Remove typhoeus altogether.  


Discussion / hints:
I'm no Ruby expert, how can we make it a soft dep?

In the meanwhile feel free to copy the HMAC code, it's licensed as MIT.
99% documentation and 1% require on first use e.g. see how Rails makes bcrypt a soft dep

https://github.com/rails/rails/blob/98b2e8a4968827beb6460174c3caf13a33487921/activemodel/lib/active_model/secure_password.rb#L42-L89


```ruby
      # To use +has_secure_password+, add bcrypt (~> 3.1.7) to your Gemfile:
      #
      #   gem 'bcrypt', '~> 3.1.7'
      def has_secure_password(attribute = :password, validations: true)
        # Load bcrypt gem only when has_secure_password is used.
        # This is to avoid ActiveModel (and by extension the entire framework)
        # being dependent on a binary library.
        begin
          require "bcrypt"
        rescue LoadError
          $stderr.puts "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install."
          raise
        end
        # etc.
```
Gotcha. I'm more inclined to just drop typhoeus altogether. Need to figure out whether this is feasible.
Yeah, if you want to support an adapter for other http clients, and want to use a gem for that, faraday is pretty standard. Otherwise, just need a consistent interface in the code

```ruby
      request = Typhoeus::Request.new(url, req_opts)
      download_file(request) if opts[:return_type] == 'File'
      request
```
I think the problem is that we get it from the open API generator, so we don't have full control over getting rid of it.
One way to achieve this would be to make typhoeus a "soft requirement" for the gem, which means that it is not necessary to install typhoeus in order to use the gem, but it may be used as an optional dependency if it is available. This can be done by modifying the gem's dependencies in its codebase to use a "soft requirement" syntax, such as `gem 'typhoeus', '~> 1.3', require: false`.

Another alternative would be to remove typhoeus as a requirement altogether, either by replacing it with another library or by removing the functionality that relies on it. This would allow the gem to be used without requiring the installation of any additional dependencies.

Ultimately, the approach that is taken will depend on the needs of the gem and its users, as well as the feasibility of implementing the requested changes.

Fix patch:
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
index 2b9298517..4b47576f9 100644
--- a/ruby/Gemfile.lock
+++ b/ruby/Gemfile.lock
@@ -2,15 +2,11 @@ PATH
   remote: .
   specs:
     svix (1.38.0)
-      typhoeus (~> 1.0, >= 1.0.1)
 
 GEM
   remote: https://rubygems.org/
   specs:
     diff-lcs (1.4.4)
-    ethon (0.14.0)
-      ffi (>= 1.38.0)
-    ffi (1.15.1)
     rake (13.0.6)
     rspec (3.10.0)
       rspec-core (~> 3.10.0)
@@ -25,8 +21,6 @@ GEM
       diff-lcs (>= 1.2.0, < 2.0)
       rspec-support (~> 3.10.0)
     rspec-support (3.10.2)
-    typhoeus (1.4.0)
-      ethon (>= 0.9.0)
 
 PLATFORMS
   ruby
diff --git a/ruby/README.md b/ruby/README.md
index ca3d839ba..f653ba8c5 100644
--- a/ruby/README.md
+++ b/ruby/README.md
@@ -50,6 +50,13 @@ Add this line to your application's Gemfile:
 gem 'svix'
 ```
 
+If you are using svix to send outgoing webhhooks, you should also install the `typhoeus` gem.
+If you are only using svix to consume incoming webhooks, you do not need it.
+
+```ruby
+gem 'typhoeus`
+```
+
 And then execute:
 
 ```sh
@@ -69,7 +76,7 @@ First checkout the [core README](../README.md#development) for details on how to
 ## Building
 
 ```sh
-bundler exec rake build
+bundle exec rake build
 ```
 
 ## Contributing
diff --git a/ruby/svix.gemspec b/ruby/svix.gemspec
index e76d59e69..5fcdf944e 100644
--- a/ruby/svix.gemspec
+++ b/ruby/svix.gemspec
@@ -15,6 +15,17 @@ Gem::Specification.new do |spec|
                        "Learn more at https://www.svix.com"
   spec.homepage      = "https://www.svix.com"
 
+  spec.post_install_message = <<~MESSAGE
+
+    Thank you for install svix!
+
+    If you are using svix to send outgoing webhhooks, you should also install the `typhoeus` gem.
+    If you are only using svix to consume incoming webhooks, you do not need it.
+
+      gem 'typhoeus`
+
+  MESSAGE
+
   # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
   # to allow pushing to a single host or delete this section to allow pushing to any host.
   if spec.respond_to?(:metadata)
@@ -45,8 +56,6 @@ Gem::Specification.new do |spec|
   spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
   spec.require_paths = ["lib"]
 
-  spec.add_runtime_dependency 'typhoeus', '~> 1.0', '>= 1.0.1'
-
   spec.add_development_dependency "rake", "~> 13.0"
   spec.add_development_dependency "rspec", "~> 3.2"
 end
diff --git a/ruby/templates/api_client_typhoeus_partial.mustache b/ruby/templates/api_client_typhoeus_partial.mustache
index 5559b96e8..41d66b894 100644
--- a/ruby/templates/api_client_typhoeus_partial.mustache
+++ b/ruby/templates/api_client_typhoeus_partial.mustache
@@ -59,6 +59,18 @@
     # @option opts [Object] :body HTTP body (JSON/XML)
     # @return [Typhoeus::Request] A Typhoeus Request
     def build_request(http_method, path, opts = {})
+
+      begin
+        require 'typhoeus'
+      rescue LoadError
+        raise <<~MESSAGE
+          To use svix for sending outgoing webhooks, you need to install the typheous gem.
+          Please add it to your Gemfile and then run `bundle install`:
+
+            gem 'typhoeus'
+        MESSAGE
+      end
+
       url = build_request_url(path, opts)
       http_method = http_method.to_sym.downcase
 


Test patch: