diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a05b8ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.env +pkg +Gemfile.lock +.DS_Store +.bundle +.idea +*.gem \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..f7200f1 --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +source 'http://rubygems.org' + +gemspec diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f1deecb --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 EnergypriceAPI + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a7787b --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +# EnergypriceAPI + +energypriceapi is the official Node.js wrapper for EnergypriceAPI.com. This allows you to quickly integrate our foreign exchange rate API and currency conversion API into your application. Check https://energypriceapi.com documentation for more information. + +## Installation +Add to Gemfile. + +``` +gem 'energypriceapi' +``` + +## Usage + +```ruby + +api_key = 'SET_YOUR_API_KEY_HERE' +client = EnergypriceAPI::Client.new(api_key: api_key) +``` +--- +## Documentation + +#### fetchSymbols() +```ruby +client.fetchSymbols() +``` + +[Link](https://energypriceapi.com/documentation#api_symbol) + +--- +#### fetchLive(base, currencies) + +- `base` <[string]> Optional. Pass in a base currency, defaults to USD. +- `currencies` <[Array]<[string]>> Optional. Pass in an array of currencies to return values for. + +```ruby +client.fetchLive(base='USD', currencies=['BRENT','GASOLINE','NATURALGAS','WTI']) +``` + +[Link](https://energypriceapi.com/documentation#api_realtime) + +--- +#### fetchHistorical(date, base, currencies) + +- `date` <[string]> Required. Pass in a string with format `YYYY-MM-DD` +- `base` <[string]> Optional. Pass in a base currency, defaults to USD. +- `currencies` <[Array]<[string]>> Optional. Pass in an array of currencies to return values for. + +```ruby +client.fetchHistorical(date='2021-04-05', base='USD', currencies=['BRENT','GASOLINE','NATURALGAS','WTI']) +``` + +[Link](https://energypriceapi.com/documentation#api_historical) + +--- +#### convert(from_currency, to_currency, amount, date) + +- `from_currency` <[string]> Optional. Pass in a base currency, defaults to USD. +- `to_currency` <[string]> Required. Specify currency you would like to convert to. +- `amount` <[number]> Required. The amount to convert. +- `date` <[string]> Optional. Specify date to use historical midpoint value for conversion with format `YYYY-MM-DD`. Otherwise, it will use live exchange rate date if value not passed in. + +```ruby +client.convert(from_currency='USD', to_currency='EUR', amount=100, date='2021-04-05') +``` + +[Link](https://energypriceapi.com/documentation#api_convert) + +--- +#### timeframe(start_date, end_date, base, currencies) + +- `start_date` <[string]> Required. Specify the start date of your timeframe using the format `YYYY-MM-DD`. +- `end_date` <[string]> Required. Specify the end date of your timeframe using the format `YYYY-MM-DD`. +- `base` <[string]> Optional. Pass in a base currency, defaults to USD. +- `currencies` <[Array]<[string]>> Optional. Pass in an array of currencies to return values for. + +```ruby +client.timeframe(start_date='2021-04-05', end_date='2021-04-06', base='USD', currencies=['BRENT','GASOLINE','NATURALGAS','WTI']) +``` + +[Link](https://energypriceapi.com/documentation#api_timeframe) + +--- +#### change(start_date, end_date, base, currencies) + +- `start_date` <[string]> Required. Specify the start date of your timeframe using the format `YYYY-MM-DD`. +- `end_date` <[string]> Required. Specify the end date of your timeframe using the format `YYYY-MM-DD`. +- `base` <[string]> Optional. Pass in a base currency, defaults to USD. +- `currencies` <[Array]<[string]>> Optional. Pass in an array of currencies to return values for. + +```ruby +client.change(start_date='2021-04-05', end_date='2021-04-06', base='USD', currencies=['BRENT','GASOLINE','NATURALGAS','WTI']) +``` + +[Link](https://energypriceapi.com/documentation#api_change) + +--- +**[Official documentation](https://energypriceapi.com/documentation)** + + +--- +## FAQ + +- How do I get an API Key? + + Free API Keys are available [here](https://energypriceapi.com). + +- I want more information + + Checkout our FAQs [here](https://energypriceapi.com/faq). + + +## Support + +For support, get in touch using [this form](https://energypriceapi.com/contact). + + +[Array]: https://www.geeksforgeeks.org/ruby-data-types/ 'Array' +[number]: https://www.geeksforgeeks.org/ruby-data-types/ 'Number' +[string]: https://apidock.com/ruby/String 'String' \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..a17c006 --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'rubygems' +require 'bundler' +require 'bundler/gem_tasks' + +Bundler.setup :default, :development diff --git a/energypriceapi.gemspec b/energypriceapi.gemspec new file mode 100644 index 0000000..4f6b9ef --- /dev/null +++ b/energypriceapi.gemspec @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'energypriceapi/version' + +Gem::Specification.new do |s| + s.name = 'energypriceapi' + s.version = EnergypriceAPI::VERSION + s.authors = ['EnergypriceAPI'] + s.email = 'contact@energypriceapi.com' + s.files = Dir['{bin,lib}/**/*'] + ['README.md', 'LICENSE.md'] + s.require_paths = ['lib'] + s.homepage = 'http://github.com/energypriceapi/energypriceapi-ruby' + s.licenses = ['MIT'] + s.summary = 'Official EnergypriceAPI Ruby client.' + s.add_dependency 'faraday', '>= 1.0.0' + s.add_dependency 'faraday_middleware' +end diff --git a/example/index.rb b/example/index.rb new file mode 100644 index 0000000..4127703 --- /dev/null +++ b/example/index.rb @@ -0,0 +1,27 @@ +require_relative '../lib/energypriceapi' + +API_KEY = 'REPLACE_ME' + +EnergypriceAPI::VERSION + +client = EnergypriceAPI::Client.new( + api_key: API_KEY +) + +data = client.fetchSymbols() +puts data + +data = client.fetchLive() +puts data + +data = client.fetchHistorical('2021-04-05', 'USD', ['BRENT','GASOLINE','NATURALGAS','WTI']) +puts data + +data = client.convert('USD', 'EUR', 100, '2021-04-05') +puts data + +data = client.timeframe('2021-04-05', '2021-04-06', 'USD', ['BRENT','GASOLINE','NATURALGAS','WTI']) +puts data + +data = client.change('2021-04-05', '2021-04-06', 'USD', ['BRENT','GASOLINE','NATURALGAS','WTI']) +puts data \ No newline at end of file diff --git a/lib/energypriceapi.rb b/lib/energypriceapi.rb new file mode 100644 index 0000000..5c29861 --- /dev/null +++ b/lib/energypriceapi.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'faraday' +require 'faraday_middleware' +require 'json' +require 'logger' + +require_relative 'energypriceapi/version' +require_relative 'energypriceapi/logger' + +require_relative 'energypriceapi/errors/fault' + +require_relative 'energypriceapi/raise_error' +require_relative 'energypriceapi/connection' +require_relative 'energypriceapi/request' +require_relative 'energypriceapi/config' +require_relative 'energypriceapi/errors' +require_relative 'energypriceapi/endpoints' +require_relative 'energypriceapi/client' diff --git a/lib/energypriceapi/client.rb b/lib/energypriceapi/client.rb new file mode 100644 index 0000000..aa38dc5 --- /dev/null +++ b/lib/energypriceapi/client.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module EnergypriceAPI + class Client + include Connection + include Request + include Endpoints + + attr_accessor(*Config::ATTRIBUTES) + + def initialize(options = {}) + EnergypriceAPI::Config::ATTRIBUTES.each do |key| + send("#{key}=", options[key] || EnergypriceAPI.config.send(key)) + end + @logger ||= EnergypriceAPI::Logger.logger + end + + class << self + def configure + block_given? ? yield(Config) : Config + end + + def config + Config + end + end + end +end diff --git a/lib/energypriceapi/config.rb b/lib/energypriceapi/config.rb new file mode 100644 index 0000000..61f5e62 --- /dev/null +++ b/lib/energypriceapi/config.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module EnergypriceAPI + module Config + extend self + + ATTRIBUTES = %i[ + endpoint + api_key + proxy + user_agent + ca_path + ca_file + logger + timeout + open_timeout + ].freeze + + attr_accessor(*Config::ATTRIBUTES) + + def reset + self.endpoint = 'https://api.energypriceapi.com/v1' + self.api_key = nil + self.user_agent = "EnergypriceAPI Ruby Client/#{EnergypriceAPI::VERSION}" + self.ca_path = defined?(OpenSSL) ? OpenSSL::X509::DEFAULT_CERT_DIR : nil + self.ca_file = defined?(OpenSSL) ? OpenSSL::X509::DEFAULT_CERT_FILE : nil + self.proxy = nil + self.logger = nil + self.timeout = nil + self.open_timeout = nil + end + end + + class << self + def configure + block_given? ? yield(Config) : Config + end + + def config + Config + end + end +end + +EnergypriceAPI::Config.reset diff --git a/lib/energypriceapi/connection.rb b/lib/energypriceapi/connection.rb new file mode 100644 index 0000000..8033a56 --- /dev/null +++ b/lib/energypriceapi/connection.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module EnergypriceAPI + module Connection + private + + def headers + {} + end + + def connection + @connection ||= begin + options = { + headers: headers.merge( + 'Accept' => 'application/json; charset=utf-8', + 'Content-Type' => 'application/json' + ) + } + + options[:headers]['User-Agent'] = user_agent if user_agent + options[:proxy] = proxy if proxy + options[:ssl] = { ca_path: ca_path, ca_file: ca_file } if ca_path || ca_file + + request_options = {} + request_options[:timeout] = timeout if timeout + request_options[:open_timeout] = open_timeout if open_timeout + options[:request] = request_options if request_options.any? + + ::Faraday::Connection.new(endpoint, options) do |connection| + connection.use ::Faraday::Request::Multipart + connection.use ::Faraday::Request::UrlEncoded + connection.use ::EnergypriceAPI::Response::RaiseError + connection.use ::FaradayMiddleware::ParseJson, content_type: /\bjson$/ + connection.response :logger, logger if logger + connection.adapter ::Faraday.default_adapter + end + end + end + end +end diff --git a/lib/energypriceapi/endpoints.rb b/lib/energypriceapi/endpoints.rb new file mode 100644 index 0000000..c89bca6 --- /dev/null +++ b/lib/energypriceapi/endpoints.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'endpoints/index' \ No newline at end of file diff --git a/lib/energypriceapi/endpoints/index.rb b/lib/energypriceapi/endpoints/index.rb new file mode 100644 index 0000000..7695758 --- /dev/null +++ b/lib/energypriceapi/endpoints/index.rb @@ -0,0 +1,66 @@ +# # frozen_string_literal: true + +module EnergypriceAPI + module Endpoints + def fetchSymbols + get('symbols') + end + + def fetchLive(base = nil, currencies = nil) + options = removeEmpty({ + base: base, + currencies: (currencies || []).join(',') + }) + get('latest', options) + end + + def fetchHistorical(date, base = nil, currencies = nil) + options = removeEmpty({ + base: base, + currencies: (currencies || []).join(',') + }) + get(date, options) + end + + def convert(from_currency = nil, to_currency = nil, amount = nil, date = nil) + options = removeEmpty({ + 'from': from_currency, + 'to': to_currency, + 'amount': amount, + 'date': date + }) + get('convert', options) + end + + def timeframe(start_date, end_date, base = nil, currencies = nil) + options = removeEmpty({ + 'start_date': start_date, + 'end_date': end_date, + 'base': base, + 'currencies': (currencies || []).join(',') + }) + get('timeframe', options) + end + + def change(start_date, end_date, base = '', currencies = nil) + options = removeEmpty({ + 'start_date': start_date, + 'end_date': end_date, + 'base': base, + 'currencies': (currencies || []).join(',') + }) + get('change', options) + end + + private + + def removeEmpty(options) + options.each do |key, value| + if (!value || value == '') + options.delete(key) + end + end + options + end + end +end diff --git a/lib/energypriceapi/errors.rb b/lib/energypriceapi/errors.rb new file mode 100644 index 0000000..c2ee451 --- /dev/null +++ b/lib/energypriceapi/errors.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'errors/fault' diff --git a/lib/energypriceapi/errors/fault.rb b/lib/energypriceapi/errors/fault.rb new file mode 100644 index 0000000..0ee76f2 --- /dev/null +++ b/lib/energypriceapi/errors/fault.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module EnergypriceAPI + module Errors + class Fault < ::Faraday::ClientError + def message + response[:body]['message'] || super + end + + def headers + response[:headers] + end + end + end +end diff --git a/lib/energypriceapi/logger.rb b/lib/energypriceapi/logger.rb new file mode 100644 index 0000000..a6a0b3c --- /dev/null +++ b/lib/energypriceapi/logger.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'logger' + +module EnergypriceAPI + class Logger < ::Logger + def self.logger + @logger ||= begin + logger = new STDOUT + logger.level = Logger::WARN + logger + end + end + end +end diff --git a/lib/energypriceapi/raise_error.rb b/lib/energypriceapi/raise_error.rb new file mode 100644 index 0000000..eee06d3 --- /dev/null +++ b/lib/energypriceapi/raise_error.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module EnergypriceAPI + module Response + class RaiseError < ::Faraday::Response::Middleware + def on_complete(env) + case env[:status] + when 404 + raise Faraday::ResourceNotFound, response_values(env) + when 407 + # mimic the behavior that we get with proxy requests with HTTPS + raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") + when (400...600).freeze + raise EnergypriceAPI::Errors::Fault, response_values(env) + end + end + + def response_values(env) + { + status: env.status, + headers: env.response_headers, + body: env.body + } + end + end + end +end diff --git a/lib/energypriceapi/request.rb b/lib/energypriceapi/request.rb new file mode 100644 index 0000000..c5b1046 --- /dev/null +++ b/lib/energypriceapi/request.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module EnergypriceAPI + module Request + def get(path, options = {}) + request(:get, path, options) + end + + def post(path, options = {}) + request(:post, path, options) + end + + def put(path, options = {}) + request(:put, path, options) + end + + def delete(path, options = {}) + request(:delete, path, options) + end + + private + + # + # @param [Symbol] method - Faraday HTTP method. + # @param [String] path - URL to send. + # @param [Hash] options - :appid, :lang, :units, :endpoint, :body keys will configure the request. + # The rest will be converted to query params for GET/DELETE, or jsonified for POST/PUT. + # + # @return [Object] - the Faraday::Response#body. + # + def request(method, path, options) + options = options.dup + options[:api_key] ||= api_key if !api_key.nil? + root = options.delete(:endpoint) || endpoint + path = [root, path].join('/') + response = connection.send(method) do |request| + case method + when :get, :delete + request.url(path, options) + when :post, :put + request.path = path + request.params = { appid: options.delete(:appid) } + if options.key?(:body) + request.body = options.delete(:body).to_json + elsif !options.empty? + request.body = options.to_json + end + end + request.options.merge!(options.delete(:request)) if options.key?(:request) + end + response.body + end + end +end diff --git a/lib/energypriceapi/version.rb b/lib/energypriceapi/version.rb new file mode 100644 index 0000000..8b7cc11 --- /dev/null +++ b/lib/energypriceapi/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module EnergypriceAPI + VERSION = '1.0.1' +end