From a1d6ebcb91ca5f3e09a3ea42ba9e5d48fb27adaf Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 17 Oct 2022 10:54:49 -0500 Subject: [PATCH 1/4] :sparkles: Add a method for having multiple APIs within the same instance. Bubblez now supports having multiple APIs simultaneously. Prior to this commit, it was only possible to have a single API client (i.e. you wouldn't be able to use a single Bubblez instance/configuration for accessing both Google and Stripe). Now, however, we've switched to named instances of API configurations. This allows us to have as many APIs as we want, as long as each one has a unique name. Refs #45. --- lib/bubblez.rb | 7 +- lib/bubblez/config.rb | 72 ++- lib/bubblez/rest_client_resources.rb | 4 +- spec/bubblez/config_spec.rb | 65 +-- spec/bubblez/resources_spec.rb | 466 ++++++++++-------- spec/bubblez/rest_environment_spec.rb | 30 +- .../sinkingmoon_post_login_https.yml | 48 ++ 7 files changed, 444 insertions(+), 248 deletions(-) create mode 100644 spec/fixtures/vcr_cassettes/sinkingmoon_post_login_https.yml diff --git a/lib/bubblez.rb b/lib/bubblez.rb index 6a8870d..92c19a3 100644 --- a/lib/bubblez.rb +++ b/lib/bubblez.rb @@ -9,14 +9,19 @@ module Bubblez class Resources < RestClientResources - def initialize(api_key='') + def initialize(name, api_key='') super + @config = Bubblez.configuration[name] @package_name = Bubblez::VersionInformation.package_name @version_name = Bubblez::VersionInformation.version_name @version_code = Bubblez::VersionInformation.version_code end + def config + @config + end + def get_version_info { :name => @package_name, diff --git a/lib/bubblez/config.rb b/lib/bubblez/config.rb index 41c143f..9158c70 100644 --- a/lib/bubblez/config.rb +++ b/lib/bubblez/config.rb @@ -15,14 +15,14 @@ class << self # # @example In app/config/initializers/bubblez.rb # Bubblez.configure do |config| - # config.endpoints = [ - # { - # :type => :get, - # :location => :version, - # :authenticated => false, - # :api_key_required => false - # } - # ] + # config.add_api('someApiName', endpoints: [ + # { + # :type => :get, + # :location => :version, + # :authenticated => false, + # :api_key_required => false + # } + # ]) # end def self.configure yield(configuration) @@ -30,19 +30,69 @@ def self.configure def self.configuration @configuration ||= Configuration.new + + @configuration + end + + class Configuration + def initialize + @apis = [] + end + + def num_apis + @apis.length + end + + def [] (key = nil) + if key.nil? && @apis.length == 1 + return @apis[0] + end + + unless @apis.include? key + self.add_api(name: key) + end + + if key.is_a? Integer and key < @apis.length + return @apis[key] + end + + if key.is_a? String + return @apis.detect {|e| e.name == key} + end + + nil + end + + def add_api(name: 'Default', environments: nil, endpoints: nil) + api_config = ApiConfiguration.new name + unless environments == nil + api_config.environments = environments + end + + unless endpoints == nil + api_config.endpoints = endpoints + end + + @apis.push(api_config) + end end ## - # The configuration of the Bubblez rest client. + # The configuration of a single API within the Bubblez rest client. # # Use this class if you want to retrieve configuration values set during initialization. # - class Configuration - def initialize + class ApiConfiguration + def initialize(name = '') + @name = name @environments = Hash.new @endpoints = Hash.new end + def name + @name + end + ## # Retrieve the {RestEnvironment} object defined as part of this Configuration having a specified name. # diff --git a/lib/bubblez/rest_client_resources.rb b/lib/bubblez/rest_client_resources.rb index 3df2853..e6292c6 100644 --- a/lib/bubblez/rest_client_resources.rb +++ b/lib/bubblez/rest_client_resources.rb @@ -3,8 +3,10 @@ module Bubblez class RestClientResources + ## @TODO_jwir3: This isn't ideal. We should choose an API using the Resources.new, and then simply be able to + # retrieve environments from there. def environment(env_name = nil) - Bubblez.configuration.environment(env_name) + config.environment(env_name) end ## diff --git a/spec/bubblez/config_spec.rb b/spec/bubblez/config_spec.rb index 6b17730..2407bf1 100644 --- a/spec/bubblez/config_spec.rb +++ b/spec/bubblez/config_spec.rb @@ -3,44 +3,49 @@ describe 'Bubblez Configuration' do context '#endpoints' do - context 'when we specify an environment with two endpoints' do + context 'when we specify an api with a single environment having two endpoints' do before do Bubblez.configure do |config| - config.environments = [ - { - scheme: 'http', - host: '127.0.0.1', - port: '9002' - } - ] - - config.endpoints = [ - { - method: :get, - location: 'categories', - name: 'get_categories', - return_type: :body_as_object, - authenticated: false, - api_key_required: true, - headers: { - 'X-RapidAPI-Host': @host - } - }, - { - method: :post, - location: :students, - authenticated: true, - name: 'create_student', - return_type: :body_as_object - } - ] + config.add_api(name: 'BoredApi', + environments: [ + { + scheme: 'http', + host: '127.0.0.1', + port: '9002' + } + ], + endpoints: [ + { + method: :get, + location: 'categories', + name: 'get_categories', + return_type: :body_as_object, + authenticated: false, + api_key_required: true, + headers: { + 'X-RapidAPI-Host': @host + } + }, + { + method: :post, + location: :students, + authenticated: true, + name: 'create_student', + return_type: :body_as_object + } + ] + ) end end it 'should return that two endpoints were defined' do config = Bubblez.configuration expect(config).to_not be_nil - expect(config.endpoints.length).to eq(2) + expect(config.num_apis).to eq(1) + + boredApi = config['BoredApi'] + expect(config[0]).to_not be_nil + expect(boredApi).to_not be_nil end end end diff --git a/spec/bubblez/resources_spec.rb b/spec/bubblez/resources_spec.rb index f0d96c9..d1d8332 100644 --- a/spec/bubblez/resources_spec.rb +++ b/spec/bubblez/resources_spec.rb @@ -76,31 +76,33 @@ end end - context 'when using the listmonk API' do + context 'when using the BoredApi API' do context 'when accessed using http' do context 'when a GET request is used' do before do Bubblez.configure do |config| - config.environments = [{ - scheme: 'http', - host: 'listmonk.example.com' - }] - config.endpoints = [ - { - location: '/api/lists', - method: :get, - api_key_required: false, - authenticated: true, - encode_authorization: %i[username password], - name: "get_lists" - } - ] + config.add_api(name: 'Listmonk', + environments: [{ + scheme: 'http', + host: 'listmonk.example.com' + }], + endpoints: [ + { + location: '/api/lists', + method: :get, + api_key_required: false, + authenticated: true, + encode_authorization: %i[username password], + name: "get_lists" + } + ]) end end it 'should return a 200 ok' do VCR.use_cassette 'get_lists_authenticated' do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Listmonk').environment + # env = Bubblez::Resources.new.environment 'Listmonk' # Use a dummy login and password response = env.get_lists 'someone', '7162jahd89' @@ -113,16 +115,18 @@ context 'when using a dummy manufactured API' do context 'when accessed using https' do - context 'when accessed using a HEAD request' do - before do - Bubblez.configure do |config| - config.environments = [{ - scheme: 'https', - host: 'www.somewhere.com', - api_key: 'somemadeupkey2' - }] - end + before do + Bubblez.configure do |config| + config.add_api(name: 'DummyApi', + environments: [{ + scheme: 'https', + host: 'www.somewhere.com', + api_key: 'somemadeupkey2' + }]) end + end + + context 'when accessed using a HEAD request' do context 'when using an authorization token' do before do @@ -132,7 +136,7 @@ context 'when an api key is required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['DummyApi'].endpoints = [ { location: '/', method: :head, @@ -146,7 +150,7 @@ it 'should return a 200 ok' do VCR.use_cassette 'head_madeup_api_key_authenticated_https' do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('DummyApi').environment response = env.head_somewhere @auth_token expect(response).to_not be_nil end @@ -158,13 +162,13 @@ context 'when an API key is required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['DummyApi'].endpoints = [ { - location: '/', - method: :head, - api_key_required: true, - authenticated: false, - name: :head_somewhere + location: '/', + method: :head, + api_key_required: true, + authenticated: false, + name: :head_somewhere } ] end @@ -172,7 +176,7 @@ it 'should return a 200 ok' do VCR.use_cassette 'head_madeup_api_key_https' do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('DummyApi').environment response = env.head_somewhere expect(response).to_not be_nil end @@ -183,10 +187,21 @@ end context 'when accessed using http' do + before do + Bubblez.configure do |config| + config.add_api(name: 'DummyApi', + environments: [{ + scheme: 'http', + host: 'www.somewhere.com', + api_key: 'somemadeupkey2' + }]) + end + end + context 'when accessed using a POST request' do before do Bubblez.configure do |config| - config.environments = [{ + config['DummyApi'].environments = [{ scheme: 'https', host: '127.0.0.1', port: '9002' @@ -198,7 +213,7 @@ context 'when an api key is not required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['DummyApi'].endpoints = [ { location: :blah, api_key_required: false, @@ -212,7 +227,7 @@ it 'should respond with 200 ok' do VCR.use_cassette('post_unauthenticated_no_api_key') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('DummyApi').environment data = { email: 'eat@example.com' } @@ -229,7 +244,7 @@ context 'when accessed using a HEAD request' do before do Bubblez.configure do |config| - config.environments = [{ + config['DummyApi'].environments = [{ scheme: 'http', host: 'www.somewhere.com', api_key: 'somemadeupkey' @@ -241,7 +256,7 @@ context 'when an API key is required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['DummyApi'].endpoints = [ { location: '/', method: :head, @@ -255,7 +270,7 @@ it 'should return a 200 ok' do VCR.use_cassette 'head_madeup_api_key' do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('DummyApi').environment response = env.head_somewhere expect(response).to_not be_nil end @@ -271,7 +286,7 @@ context 'when an api key is required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['DummyApi'].endpoints = [ { location: '/', method: :head, @@ -285,7 +300,7 @@ it 'should return a 200 ok' do VCR.use_cassette 'head_madeup_api_key_authenticated' do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('DummyApi').environment response = env.head_somewhere @auth_token expect(response).to_not be_nil end @@ -297,10 +312,15 @@ end context 'when using the dummy reqres API' do + before do + Bubblez.configure do |config| + config.add_api(name: 'reqres') + end + end context 'accessed using https' do before do Bubblez.configure do |config| - config.environments = [{ + config['reqres'].environments = [{ scheme: 'https', host: 'reqres.in' }] @@ -310,7 +330,7 @@ context 'when accessing the users endpoint without authentication' do before do Bubblez.configure do |config| - config.endpoints = [ + config['reqres'].endpoints = [ { method: :get, location: 'api/users/{id}', @@ -321,7 +341,7 @@ } ] - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new('reqres') end end @@ -345,6 +365,9 @@ context 'when using the joke API' do before do + Bubblez.configure do |config| + config.add_api(name: 'Joke Api') + end @host = 'jokeapi.p.rapidapi.com' end @@ -354,7 +377,7 @@ @api_key = 'f950bc6c01msh14699dc76e5c505p1299d6jsncc2bf32a60af' Bubblez.configure do |config| - config.endpoints = [ + config['Joke Api'].endpoints = [ { method: :get, location: 'categories', @@ -368,7 +391,7 @@ } ] - config.environments = [{ + config['Joke Api'].environments = [{ scheme: 'https', host: @host, api_key: @api_key, @@ -379,7 +402,7 @@ it 'should return four categories for jokes that can be retrieved' do VCR.use_cassette('get_jokeapi_categories') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new('Joke Api') environment = resources.environment response = environment.get_categories @@ -394,11 +417,11 @@ context 'when using the FoamFactory API, accessed remotely' do before do Bubblez.configure do |config| - config.environments = [{ + config.add_api(name: 'FoamFactory', environments: [{ scheme: 'https', host: 'api.foamfactory.io', api_key: '0c4e97c2f7af608117e519d941f1d2fbc25fe46a' - }] + }]) end end @@ -407,7 +430,7 @@ context 'with an authenticated endpoint requiring an API key' do before do Bubblez.configure do |config| - config.endpoints = [ + config['FoamFactory'].endpoints = [ { location: :login, method: :post, @@ -428,7 +451,7 @@ it 'should successfully list all users in the system' do VCR.use_cassette('get_all_users_foamfactory_remote') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('FoamFactory').environment authenticated_user = env.login 'scottj', '123qwe456' expect(authenticated_user).to_not be_nil @@ -447,12 +470,12 @@ context 'when using the FoamFactory API, accessed locally' do before do Bubblez.configure do |config| - config.environments = [{ - scheme: 'http', - host: 'localhost', - port: 1234, - api_key: 'fc411dc1b9bcc75f113951e574e243cca92fbddc' - }] + config.add_api(name: 'FoamFactory-Local', environments: [{ + scheme: 'http', + host: 'localhost', + port: 1234, + api_key: 'fc411dc1b9bcc75f113951e574e243cca92fbddc' + }]) end end @@ -461,7 +484,7 @@ context 'with an authenticated API requiring an API key' do before do Bubblez.configure do |config| - config.endpoints = [ + config['FoamFactory-Local'].endpoints = [ { location: :login, method: :post, @@ -482,7 +505,7 @@ it 'should successfully list all users in the system' do VCR.use_cassette('get_all_users_foamfactory_local') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('FoamFactory-Local').environment authenticated_user = env.login 'scottj', '123qwe456' expect(authenticated_user).to_not be_nil @@ -501,12 +524,12 @@ context 'when using the SinkingMoon API' do before do Bubblez.configure do |config| - config.environments = [{ + config.add_api(name: 'Sinking Moon', environments: [{ scheme: 'http', host: '127.0.0.1', port: '9002', api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' - }] + }]) end end @@ -514,7 +537,7 @@ context 'when the host is unavailable' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :post, location: :students, @@ -524,7 +547,7 @@ } ] - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'https', host: '127.0.0.1', port: '1234', @@ -554,7 +577,7 @@ waiverSigned: true } - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment student = environment.create_student 'someauthtoken', data @@ -569,7 +592,7 @@ context 'and accessed using https' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :post, location: 'password/forgot', @@ -580,7 +603,7 @@ } ] - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'https', host: '127.0.0.1', port: '9002', @@ -591,7 +614,7 @@ it 'should successfully send a request to the server at the correct location' do VCR.use_cassette('post_unauthenticated_slash_in_path_https') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment data = { email: 'eat@example.com' } @@ -607,7 +630,13 @@ context 'when the endpoint has encoded authorization' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].environments = [{ + scheme: 'http', + host: '127.0.0.1', + port: '9002', + api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' + }] + config['Sinking Moon'].endpoints = [ { method: :post, location: :login, @@ -622,7 +651,7 @@ it 'should retrieve an authorization token' do VCR.use_cassette('login') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment # data = { username: 'scottj', password: '123qwe456' } @@ -640,7 +669,7 @@ context 'when an authorization token is required' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :post, location: :students, @@ -662,7 +691,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -701,7 +730,7 @@ context 'and an API key is required in the header X-Something-Key' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'http', host: '127.0.0.1', port: '9002', @@ -709,7 +738,7 @@ api_key: 'blahblahblah' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :post, location: :students, @@ -724,7 +753,7 @@ it 'should correctly add a record using a POST request' do VCR.use_cassette('post_student_authenticated_api_key') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment data = { name: 'Scott Klein', @@ -754,14 +783,14 @@ context 'when using https' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'https', host: '127.0.0.1', port: '9002', api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :post, location: :students, @@ -777,7 +806,7 @@ it 'should correctly add a record using a POST request' do VCR.use_cassette('post_student_authenticated_https') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment data = { name: 'Scott Klein', @@ -813,7 +842,13 @@ context 'for an endpoint that does not require an api key' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].environments = [{ + scheme: 'http', + host: '127.0.0.1', + port: '9002', + api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' + }] + config['Sinking Moon'].endpoints = [ { method: :get, location: :version, @@ -827,7 +862,7 @@ it 'should be able to retrieve a response from the API' do VCR.use_cassette('get_version_unauthenticated') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment response = environment.version @@ -847,7 +882,7 @@ context 'that requires an authorization token' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :get, location: :students, @@ -877,7 +912,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -916,7 +951,7 @@ context 'for an endpoint that requires no authentication' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :get, location: :version, @@ -930,7 +965,7 @@ it 'should be able to retrieve a response from the API' do VCR.use_cassette('get_version_unauthenticated') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment response = environment.version @@ -944,7 +979,7 @@ context 'that requires an authorization token' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :get, location: :students, @@ -974,7 +1009,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -1009,7 +1044,7 @@ context 'for an endpoint that requires no authentication' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :get, location: :version, @@ -1023,7 +1058,7 @@ it 'should be able to retrieve a response from the API' do VCR.use_cassette('get_version_unauthenticated') do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Sinking Moon' environment = resources.environment response = environment.version @@ -1045,7 +1080,7 @@ context 'that requires an authorization token' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :get, location: :students, @@ -1075,7 +1110,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -1119,7 +1154,7 @@ it 'should raise an exception' do expect { Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :delete, location: 'students', @@ -1138,14 +1173,14 @@ context 'with a valid api key' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'http', host: '127.0.0.1', port: 9002, api_key: 'blahblahblah' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :delete, location: 'students/{id}', @@ -1164,7 +1199,7 @@ id: 2 } - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment response = env.delete_student_no_auth uri_params expect(response).to_not be_nil @@ -1177,7 +1212,7 @@ context 'for an endpoint that requires authorization' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :delete, location: 'students/{id}', @@ -1192,13 +1227,13 @@ context 'when accessing a host via HTTPS that requires an API key' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'https', host: 'testbed.foamfactory.io', api_key: 'blahblahblah' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :delete, location: 'students/{id}', @@ -1214,7 +1249,7 @@ it 'should successfully delete the record' do VCR.use_cassette('delete_student_by_id_api_key_https') do auth_token = 'eyJhbGciOiJIUzI1NiJ9.eyJjcmVhdGlvbl9kYXRlIjoiMjAxOS0wNC0yOFQxMDo0NDo0MS0wNTowMCIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMTktMDUtMjhUMTA6NDQ6NDEtMDU6MDAiLCJ1c2VyX2lkIjoxfQ.C1mSYJ7ho6Cly8Ik_BcDzfC6rKb6cheY-NMbXV7QWvE' - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment response = env.delete_student_https auth_token, {id: 2} expect(response.success).to eq(true) @@ -1224,7 +1259,23 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + Bubblez.configure do |config| + config['Sinking Moon'].environments = [{ + scheme: 'http', + host: '127.0.0.1', + port: 9002, + api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' + }] + config['Sinking Moon'].endpoints = [{ + method: :post, + location: :login, + authenticated: false, + api_key_required: true, + encode_authorization: %i[username password], + return_type: :body_as_object + }] + end + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -1252,7 +1303,7 @@ context 'for an endpoint that does not have URI parameters' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'password/change', @@ -1273,7 +1324,7 @@ password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment response = env.change_password_no_uri 'blahblahblah', data expect(response).to_not be_nil @@ -1284,7 +1335,7 @@ before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'students/{id}', @@ -1306,7 +1357,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new('Sinking Moon') @environment = @resources.environment VCR.use_cassette('login') do @@ -1319,13 +1370,13 @@ context 'when using https and an api key is required' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'https', host: '127.0.0.1', api_key: 'e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'students/{id}', @@ -1340,7 +1391,7 @@ it 'should update part of a record' do VCR.use_cassette('patch_update_student_https') do - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment response = env.update_student @auth_token, {id: 4}, {student: {email: 'kleinhammer@gmail.com' } } expect(response.id).to eq(4) @@ -1377,7 +1428,7 @@ context 'for an endpoint that does not require authentication' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'password/change', @@ -1387,7 +1438,7 @@ } ] - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment end end @@ -1401,13 +1452,13 @@ context 'when using https and passing an API key' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: :https, host: 'api.something.com', api_key: 'blahblahblahblah' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, authenticated: false, @@ -1428,7 +1479,7 @@ password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + env = Bubblez::Resources.new('Sinking Moon').environment response = env.change_forgotten_password data expect(response).to_not be_nil @@ -1436,27 +1487,17 @@ end end end - - it 'should allow the successful execution of the request' do - VCR.use_cassette('patch_change_password_unauthenticated') do - data = { - one_time_login_hash: @hash, - new_password: @new_password, - password_confirmation: @new_password - } - - response = @environment.change_forgotten_password data - - expect(response).to_not be_nil - expect(response.success).to be_truthy - end - end end context 'for an endpoint that requires URI parameters' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].environments = [{ + scheme: :http, + host: '127.0.0.1', + port: 9002 + }] + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'password/change/{hash}', @@ -1485,7 +1526,8 @@ password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.change_forgotten_password_uri uri_params, data expect(response).to_not be_nil @@ -1502,7 +1544,7 @@ context 'with an invalid identification parameter' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :patch, location: 'password/change', @@ -1513,7 +1555,7 @@ ] end - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment @hash = '0xdeadbeef' @@ -1549,7 +1591,7 @@ context 'for an endpoint that does not have URI parameters' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'password/change', @@ -1570,7 +1612,8 @@ password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.change_password_no_uri 'blahblahblah', data expect(response).to_not be_nil @@ -1581,7 +1624,7 @@ before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'students/{id}', @@ -1603,7 +1646,7 @@ context 'with a valid authorization token' do before do - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment VCR.use_cassette('login') do @@ -1616,7 +1659,7 @@ context 'when accessed using https and an api key' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'students/{id}', @@ -1627,7 +1670,7 @@ } ] - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: :https, host: 'testbed.foamfactory.io', api_key: 'blahblahblah' @@ -1651,7 +1694,8 @@ } } - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.update_student @auth_token, {id: 4}, data expect(response.id).to eq(4) @@ -1704,7 +1748,7 @@ context 'for an endpoint that does not require authentication' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'password/change', @@ -1714,7 +1758,7 @@ } ] - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment end end @@ -1728,13 +1772,13 @@ context 'when accessed with https and an API key' do before do Bubblez.configure do |config| - config.environments = [{ - scheme: :https, - host: 'testbed.foamfactory.io', - api_key: 'foamfactorybeermaker' + config['Sinking Moon'].environments = [{ + scheme: :http, + host: '127.0.0.1', + port: 9002 }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'password/change', @@ -1746,15 +1790,58 @@ ] end end + + context 'when using https instead of http' do + before do + Bubblez.configure do |config| + config['Sinking Moon'].environments = [{ + scheme: :https, + host: 'testbed.foamfactory.io', + api_key: 'foamfactorybeermaker' + }] + end + end + + it 'should allow the successful execution of the request' do + VCR.use_cassette('put_change_password_unauthenticated_https') do + data = { + one_time_login_hash: @hash, + new_password: @new_password, + password_confirmation: @new_password + } + + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment + response = env.change_forgotten_password_put data + + expect(response).to_not be_nil + expect(response.success).to be_truthy + end + end + end + end + + context 'when using http' do + before do + Bubblez.configure do |config| + config['Sinking Moon'].environments = [{ + scheme: :http, + host: '127.0.0.1', + port: 9002 + }] + end + end + it 'should allow the successful execution of the request' do - VCR.use_cassette('put_change_password_unauthenticated_https') do + VCR.use_cassette('put_change_password_unauthenticated') do data = { one_time_login_hash: @hash, new_password: @new_password, password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.change_forgotten_password_put data expect(response).to_not be_nil @@ -1762,27 +1849,12 @@ end end end - - it 'should allow the successful execution of the request' do - VCR.use_cassette('put_change_password_unauthenticated') do - data = { - one_time_login_hash: @hash, - new_password: @new_password, - password_confirmation: @new_password - } - - response = @environment.change_forgotten_password_put data - - expect(response).to_not be_nil - expect(response.success).to be_truthy - end - end end context 'for an endpoint that requires URI parameters' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'password/change/{hash}', @@ -1811,7 +1883,8 @@ password_confirmation: @new_password } - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.change_forgotten_password_uri uri_params, data expect(response).to_not be_nil @@ -1828,7 +1901,7 @@ context 'with an invalid identification parameter' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :put, location: 'password/change', @@ -1839,7 +1912,7 @@ ] end - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' @environment = @resources.environment @hash = '0xdeadbeef' @@ -1873,7 +1946,7 @@ context 'for an endpoint that does not require authorization' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'http', host: '127.0.0.1', port: '1234', @@ -1886,13 +1959,13 @@ context 'when at least one url parameter is expected' do before do Bubblez.configure do |config| - config.environments = [{ + config['Sinking Moon'].environments = [{ scheme: 'http', host: '127.0.0.1', port: '1234' }] - config.endpoints = [ + config['Sinking Moon'].endpoints = [ method: :head, name: 'validate_login_hash', location: '/validate/{hash}', @@ -1901,7 +1974,7 @@ ] end - @resources = Bubblez::Resources.new + @resources = Bubblez::Resources.new 'Sinking Moon' end context 'and that url parameter is specified on the url path and is not valid' do @@ -1943,7 +2016,7 @@ context 'when at least one url parameter is expected' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ method: :head, name: 'validate_login_hash', location: '/validate/{hash}', @@ -1952,8 +2025,6 @@ return_type: :full_response ] end - - @resources = Bubblez::Resources.new end context 'and that url parameter is specified on the url path and is not valid' do @@ -1964,8 +2035,10 @@ it 'should return a 401 unauthorized' do VCR.use_cassette('head_api_key_validate_login_hash_with_invalid_hash') do saw_error = false + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment begin - response = @resources.environment.validate_login_hash({hash: @login_hash}) + response = env.validate_login_hash({hash: @login_hash}) rescue RestClient::Unauthorized saw_error = true end @@ -1981,7 +2054,9 @@ end it 'should return a 204 no_content' do VCR.use_cassette('head_api_key_validate_login_hash_with_valid_hash') do - response = @resources.environment.validate_login_hash({hash: @login_hash}) + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment + response = env.validate_login_hash({hash: @login_hash}) expect(response).to_not be_nil expect(response.code).to eq(204) @@ -1996,13 +2071,13 @@ context 'after redefining the environment to use Google with additional headers' do before do Bubblez.configure do |config| - config.environments = [{ + config['Google'].environments = [{ scheme: 'http', host: 'www.google.com', port: '80' }] - config.endpoints = [ + config['Google'].endpoints = [ { method: :head, location: '/', @@ -2015,13 +2090,13 @@ } ] end - - @resources = Bubblez::Resources.new end it 'should add the header to the request' do VCR.use_cassette('head_google_with_headers') do - response = @resources.environment.head_google + resources = Bubblez::Resources.new 'Google' + env = resources.environment + response = env.head_google request = response.request expect(request).to_not be_nil @@ -2035,13 +2110,13 @@ # NOTE - this is required so we know that we can redefine environments without issues before do Bubblez.configure do |config| - config.environments = [{ + config['Google'].environments = [{ scheme: 'http', host: 'www.google.com', port: '80' }] - config.endpoints = [ + config['Google'].endpoints = [ { method: :head, location: '/', @@ -2051,13 +2126,13 @@ } ] end - - @resources = Bubblez::Resources.new end it 'should return a 200 Ok response' do VCR.use_cassette('head_google') do - response = @resources.environment.head_google + resources = Bubblez::Resources.new 'Google' + env = resources.environment + response = env.head_google expect(response).to_not be_nil expect(response.code).to eq(200) @@ -2071,7 +2146,7 @@ context 'for an endpoint that requires authorization' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].endpoints = [ { method: :head, location: '/students', @@ -2095,7 +2170,12 @@ context 'having URI parameters specified' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Sinking Moon'].environments = [{ + scheme: 'http', + host: '127.0.0.1', + port: '9002' + }] + config['Sinking Moon'].endpoints = [ method: :head, authenticated: true, api_key_required: false, @@ -2107,7 +2187,8 @@ it 'should return a 200 ok response' do VCR.use_cassette('head_students_authenticated_uri_params') do - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment response = env.head_student_by_id 'blahblahblah', { id: 32 } expect(response).to_not be_nil @@ -2118,11 +2199,10 @@ context 'with no URI parameters' do before do - @resources = Bubblez::Resources.new - @environment = @resources.environment - VCR.use_cassette('login') do - login_object = @environment.login 'scottj', '123qwe456' + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment + login_object = env.login 'scottj', '123qwe456' @auth_token = login_object.auth_token end @@ -2130,7 +2210,9 @@ it 'should return a 200 ok response' do VCR.use_cassette('head_students_authenticated') do - response = @environment.head_students @auth_token + resources = Bubblez::Resources.new 'Sinking Moon' + env = resources.environment + response = env.head_students @auth_token expect(response).to_not be_nil expect(response.code).to eq(200) diff --git a/spec/bubblez/rest_environment_spec.rb b/spec/bubblez/rest_environment_spec.rb index 6f8b4d0..176b047 100644 --- a/spec/bubblez/rest_environment_spec.rb +++ b/spec/bubblez/rest_environment_spec.rb @@ -6,7 +6,7 @@ context 'for an environment that specifies a scheme of http and a default port' do before do Bubblez.configure do |config| - config.environments = [{ + config['Default'].environments = [{ scheme: 'http', host: 'somewhere.something.net', }] @@ -14,7 +14,8 @@ end it 'should actually set the port to 80' do - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Default' + env = resources.environment expect(env.port).to eq(80) end end @@ -22,7 +23,7 @@ context 'for an environment that specifies a scheme of https and a default port' do before do Bubblez.configure do |config| - config.environments = [{ + config['Default'].environments = [{ scheme: 'https', host: 'somewhere.something.net', }] @@ -30,7 +31,8 @@ end it 'should actually set the port to 443' do - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Default' + env = resources.environment expect(env.port).to eq(443) end end @@ -39,7 +41,7 @@ describe 'Bubblez::Configure' do before do Bubblez.configure do |config| - config.endpoints = [ + config['Default'].endpoints = [ { method: :get, location: :students, @@ -61,7 +63,7 @@ } ] - config.environments = [{ + config['Default'].environments = [{ scheme: 'http', host: '127.0.0.1', port: '1234', @@ -86,7 +88,7 @@ describe '#environments' do before do Bubblez.configure do |config| - config.environments = [{ + config['Default'].environments = [{ scheme: 'https', host: '127.0.1.1', port: '2222', @@ -99,7 +101,7 @@ it 'should raise an exception' do expect { Bubblez.configure do |config| - config.environments = [ + config['Default'].environments = [ { scheme: 'https', host: '127.0.1.1', @@ -117,7 +119,7 @@ end it 'returns an address of https://127.0.1.1:2222' do - resources = Bubblez::Resources.new + resources = Bubblez::Resources.new 'Default' environment = resources.environment 'local' expect(environment).to_not be_nil @@ -131,7 +133,7 @@ context 'for an environment that has an API key name specified' do before do Bubblez.configure do |config| - config.environments = [{ + config['Default'].environments = [{ scheme: 'https', host: '127.0.1.1', port: '2222', @@ -142,7 +144,8 @@ end it 'should return the name of the API key' do - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Default' + env = resources.environment expect(env.api_key_name).to eq('X-Something-Key') end end @@ -150,7 +153,7 @@ context 'for an environment that does not have an API key name specified' do before do Bubblez.configure do |config| - config.environments = [{ + config['Default'].environments = [{ scheme: 'https', host: '127.0.1.1', port: '2222', @@ -160,7 +163,8 @@ end it 'should return "X-API-Key"' do - env = Bubblez::Resources.new.environment + resources = Bubblez::Resources.new 'Default' + env = resources.environment expect(env.api_key_name).to eq('X-API-Key') end end diff --git a/spec/fixtures/vcr_cassettes/sinkingmoon_post_login_https.yml b/spec/fixtures/vcr_cassettes/sinkingmoon_post_login_https.yml new file mode 100644 index 0000000..c5ab3d5 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/sinkingmoon_post_login_https.yml @@ -0,0 +1,48 @@ +--- +http_interactions: + - request: + method: post + uri: https://127.0.0.1:9002/login + body: + encoding: UTF-8 + string: "{}" + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + User-Agent: + - rest-client/2.0.2 (darwin18.5.0 x86_64) ruby/2.4.1p111 + X-Api-Key: + - e5528cb7ee0c5f6cb67af63c8f8111dce91a23e6 + Authorization: + - Basic c2NvdHRqOjEyM3F3ZTQ1Ng== + Content-Type: + - application/json + Content-Length: + - '2' + Host: + - 127.0.0.1:9002 + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + Etag: + - W/"e46a1461e99dc9c2db75d7c5827f285e" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - aac15e83-cc16-42b6-afa2-ddd1c78cec94 + X-Runtime: + - '0.149320' + Transfer-Encoding: + - chunked + body: + encoding: UTF-8 + string: '{"id":1,"name":"Scott Johnson","username":"scottj","email":"scottj@sinkingmoon.com","validation_hash":null,"validation_expire_date":null,"email_validated":true,"created_at":"2019-04-28T15:30:59.105Z","updated_at":"2019-04-28T15:44:41.909Z","role":"admin","auth_token":"eyJhbGciOiJIUzI1NiJ9.eyJjcmVhdGlvbl9kYXRlIjoiMjAxOS0wNC0yOFQxMDo0NDo0MS0wNTowMCIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMTktMDUtMjhUMTA6NDQ6NDEtMDU6MDAiLCJ1c2VyX2lkIjoxfQ.C1mSYJ7ho6Cly8Ik_BcDzfC6rKb6cheY-NMbXV7QWvE","one_time_login_hash":null,"one_time_login_hash_expire_date":null}' + http_version: + recorded_at: Sun, 28 Apr 2019 23:01:49 GMT +recorded_with: VCR 3.0.3 From ac9bb5aff226c764ad4f596cc66600fafedcc48e Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 17 Oct 2022 11:28:47 -0500 Subject: [PATCH 2/4] :book: Add a badge for build status to the README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dc88b4..dee5d8a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # bubblez -[![Build Status](https://travis-ci.org/FoamFactory/bubbles.svg?branch=master)](https://travis-ci.org/FoamFactory/bubbles) +[![Build Status](https://github.com/FoamFactory/bubblez/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/FoamFactory/bubblez/actions/workflows/test.yml) A gem for easily defining client REST interfaces in ruby From 43853b4fd496ccdc6eace3b270aab0d6d35624f7 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 17 Oct 2022 11:33:16 -0500 Subject: [PATCH 3/4] :book: Update README for version 2. --- README.md | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index dee5d8a..6cd5955 100644 --- a/README.md +++ b/README.md @@ -38,25 +38,28 @@ In `config/initializers/bubblez.rb`, add the following: require 'bubblez' Bubblez.configure do |config| - config.endpoints = [ - { - :method => :get, - :location => :version, - :authenticated => false, - :api_key_required => false - } - ] - - config.environments = [{ - :scheme => 'http', - :host => '0.0.0.0', - :port => '1234' - }] + config.add_api(name: 'MyApi', + environments: [{ + :scheme => 'http', + :host => '0.0.0.0', + :port => '1234' + }], + endpoints: [ + { + :method => :get, + :location => :version, + :authenticated => false, + :api_key_required => false + } + ]) end ``` -The `config.endpoints` section is where you configure which endpoints you want to support. The `config.environments` -defines the environments, or remote configurations, for accessing the endpoint on specific remote destinations. +The `config` object is the root of the `bubblez` configuration. It contains one or more API configurations, each added using the `add_api` method. Each API configuration must have a unique name. + +The `endpoints` parameter of the method is where you configure which endpoints you want to support. +The `environments` parameter of the method defines the environments, or remote configurations, for accessing the +endpoints on specific remote destinations. Now, you can use this endpoint with: ```ruby @@ -64,7 +67,7 @@ require 'bubblez' ... def version - resources = Bubbles::Resources.new + resources = Bubblez::Resources.new 'Default' # The following will make a GET request to # http://0.0.0.0:1234/version and return the result. @@ -74,5 +77,6 @@ def version end ``` + ## Detailed Documentation For more examples and detailed documentation, please see [the Bubblez GitHub page](http://foamfactory.github.io/bubblez). From ce0ebe2f7315a9d401c8b502e9a636466f33b279 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 17 Oct 2022 11:33:53 -0500 Subject: [PATCH 4/4] :arrow_up: Bump version to 2.0.0. --- lib/bubblez/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bubblez/version.rb b/lib/bubblez/version.rb index 2c1eeca..fdb3a35 100644 --- a/lib/bubblez/version.rb +++ b/lib/bubblez/version.rb @@ -7,7 +7,7 @@ def self.package_name end def self.version_name - '1.0.1' + '2.0.0' end def self.version_code