From 73b10f54ca43f092d5f8572dbd635e67572bae36 Mon Sep 17 00:00:00 2001 From: Tejas Date: Mon, 23 Dec 2024 22:17:21 +0530 Subject: [PATCH] Dynamic API Key support (#85) --- README.md | 17 ++++- lib/resend/request.rb | 6 +- spec/api_keys_spec.rb | 154 +++++++++++++++++++++++++++++------------- 3 files changed, 128 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index e0b4e43..64f05c6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ![Build](https://github.com/drish/resend-ruby/actions/workflows/build.yml/badge.svg) [![Gem Version](https://badge.fury.io/rb/resend.svg)](https://badge.fury.io/rb/resend) + --- ## Installation @@ -10,11 +11,13 @@ To install Resend Ruby and Rails SDK, simply execute the following command in a terminal: Via RubyGems: + ``` gem install resend ``` Via Gemfile: + ``` gem 'resend' ``` @@ -37,6 +40,19 @@ Resend.configure do |config| end ``` +The `#api_key` method also accepts a block without arguments, which can be useful for lazy or dynamic loading of API keys. + +```ruby +require "resend" +Resend.api_key = -> { ENV["RESEND_API_KEY"] } +``` + +```ruby +Resend.configure do |config| + config.api_key = -> { Current.user.resend_api_key } # Assumes the user has a `resend_api_key` attribute. +end +``` + ## Example ```rb @@ -56,7 +72,6 @@ puts r You can view all the examples in the [examples folder](https://github.com/drish/resend-ruby/tree/main/examples) - # Rails and ActiveMailer support This gem can be used as an ActionMailer delivery method, add this to your `config/environments/environment.rb` file. diff --git a/lib/resend/request.rb b/lib/resend/request.rb index a7a436e..ec8ee5d 100644 --- a/lib/resend/request.rb +++ b/lib/resend/request.rb @@ -13,7 +13,9 @@ class Request attr_accessor :body, :verb def initialize(path = "", body = {}, verb = "POST") - raise if Resend.api_key.nil? + raise if (api_key = Resend.api_key).nil? + + api_key = api_key.call if api_key.is_a?(Proc) @path = path @body = body @@ -22,7 +24,7 @@ def initialize(path = "", body = {}, verb = "POST") "Content-Type" => "application/json", "Accept" => "application/json", "User-Agent" => "resend-ruby:#{Resend::VERSION}", - "Authorization" => "Bearer #{Resend.api_key}" + "Authorization" => "Bearer #{api_key}" } end diff --git a/spec/api_keys_spec.rb b/spec/api_keys_spec.rb index 932fb1c..a411b67 100644 --- a/spec/api_keys_spec.rb +++ b/spec/api_keys_spec.rb @@ -1,63 +1,125 @@ # frozen_string_literal: true RSpec.describe "API Keys" do - - describe "create" do - + context 'static api_key' do before do Resend.configure do |config| config.api_key = "re_123" end end - it "should create api key" do - resp = { - "id": "dacf4072-4119-4d88-932f-6202748ac7c8", - "token": "re_c1tpEyD8_NKFusih9vKVQknRAQfmFcWCv" - } - params = { - "name": "production" - } - allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) - expect(Resend::ApiKeys.create(params)[:id]).to eql("dacf4072-4119-4d88-932f-6202748ac7c8") - end - - it "should raise when permission is invalid" do - resp = { - "statusCode" => 422, - "name" => "invalid_permission", - "message" => "Access must be 'full_access' | 'sending_access'" - } - allow(resp).to receive(:body).and_return(resp) - params = { - "name": "production", - "permission": "invalid" - } - allow(HTTParty).to receive(:send).and_return(resp) - expect { Resend::ApiKeys.create params }.to raise_error(Resend::Error::InvalidRequestError, /Access must be 'full_access' | 'sending_access'/) + describe "create" do + + it "should create api key" do + resp = { + "id": "dacf4072-4119-4d88-932f-6202748ac7c8", + "token": "re_c1tpEyD8_NKFusih9vKVQknRAQfmFcWCv" + } + params = { + "name": "production" + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + expect(Resend::ApiKeys.create(params)[:id]).to eql("dacf4072-4119-4d88-932f-6202748ac7c8") + end + + it "should raise when permission is invalid" do + resp = { + "statusCode" => 422, + "name" => "invalid_permission", + "message" => "Access must be 'full_access' | 'sending_access'" + } + allow(resp).to receive(:body).and_return(resp) + params = { + "name": "production", + "permission": "invalid" + } + allow(HTTParty).to receive(:send).and_return(resp) + expect { Resend::ApiKeys.create params }.to raise_error(Resend::Error::InvalidRequestError, /Access must be 'full_access' | 'sending_access'/) + end end - end - describe "list" do - it "should list api keys" do - resp = { - "data": [ - { - "id":"6e3c3d83-05dc-4b51-acfc-fe8972738bd0", - "name":"test1", - "created_at":"2023-04-21T01:31:02.671414+00:00" - } - ] - } - allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) - expect(Resend::ApiKeys.list.length).to eql(1) + describe "list" do + it "should list api keys" do + resp = { + "data": [ + { + "id":"6e3c3d83-05dc-4b51-acfc-fe8972738bd0", + "name":"test1", + "created_at":"2023-04-21T01:31:02.671414+00:00" + } + ] + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + expect(Resend::ApiKeys.list.length).to eql(1) + end + end + + describe "remove" do + it "should remove api key" do + allow_any_instance_of(Resend::Request).to receive(:perform).and_return("") + expect { Resend::ApiKeys.remove }.not_to raise_error + end end end - describe "remove" do - it "should remove api key" do - allow_any_instance_of(Resend::Request).to receive(:perform).and_return("") - expect { Resend::ApiKeys.remove }.not_to raise_error + context 'dynamic api_key' do + before do + Resend.configure do |config| + config.api_key = -> { "re_123" } + end + end + + describe "create" do + + it "should create api key" do + resp = { + "id": "dacf4072-4119-4d88-932f-6202748ac7c8", + "token": "re_c1tpEyD8_NKFusih9vKVQknRAQfmFcWCv" + } + params = { + "name": "production" + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + expect(Resend::ApiKeys.create(params)[:id]).to eql("dacf4072-4119-4d88-932f-6202748ac7c8") + end + + it "should raise when permission is invalid" do + resp = { + "statusCode" => 422, + "name" => "invalid_permission", + "message" => "Access must be 'full_access' | 'sending_access'" + } + allow(resp).to receive(:body).and_return(resp) + params = { + "name": "production", + "permission": "invalid" + } + allow(HTTParty).to receive(:send).and_return(resp) + expect { Resend::ApiKeys.create params }.to raise_error(Resend::Error::InvalidRequestError, /Access must be 'full_access' | 'sending_access'/) + end + end + + describe "list" do + it "should list api keys" do + resp = { + "data": [ + { + "id":"6e3c3d83-05dc-4b51-acfc-fe8972738bd0", + "name":"test1", + "created_at":"2023-04-21T01:31:02.671414+00:00" + } + ] + } + allow_any_instance_of(Resend::Request).to receive(:perform).and_return(resp) + expect(Resend::ApiKeys.list.length).to eql(1) + end + end + + describe "remove" do + it "should remove api key" do + allow_any_instance_of(Resend::Request).to receive(:perform).and_return("") + expect { Resend::ApiKeys.remove }.not_to raise_error + end end end end