-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
467 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Change Log | ||
|
||
All notable changes to this project will be documented in this file. | ||
|
||
## [0.1.4] - 2019-11-11 | ||
|
||
- Add `Customer` resource | ||
- Add `json` and `faraday` gems | ||
|
||
## [0.1.0] - 2019-11-08 | ||
|
||
- Init project | ||
|
||
### Added | ||
|
||
- Added ability to request data. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
require "bundler/gem_tasks" | ||
require "rspec/core/rake_task" | ||
require 'bundler/gem_tasks' | ||
require 'rspec/core/rake_task' | ||
|
||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
task :default => :spec | ||
task default: :spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,12 @@ | ||
require 'unleashed/version' | ||
require_relative 'unleashed/client' | ||
require_relative 'unleashed/default' | ||
require_relative 'unleashed/error' | ||
require_relative 'unleashed/version' | ||
|
||
module Unleashed | ||
# Your code goes here... | ||
class << self | ||
include Unleashed::Configurable | ||
end | ||
end | ||
|
||
Unleashed.setup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
require_relative 'configurable' | ||
require_relative 'error' | ||
require_relative 'models/base_model' | ||
require_relative 'models/customer' | ||
require_relative 'resources/base_resource' | ||
require_relative 'resources/customer_resource' | ||
require 'json' | ||
require 'faraday' | ||
|
||
module Unleashed | ||
# Client for the Unleashed API | ||
# | ||
# @see https://apidocs.unleashedsoftware.com | ||
class Client | ||
include Unleashed::Configurable | ||
|
||
def initialize(options = {}) | ||
# Use options passed in, but fall back to module defaults | ||
Unleashed::Configurable.keys.each do |key| | ||
instance_variable_set( | ||
:"@#{key}", options[key] || Unleashed.instance_variable_get(:"@#{key}") | ||
) | ||
end | ||
end | ||
|
||
# Create a new Faraday connection | ||
# | ||
# @return [Faraday::Connection] | ||
def connection | ||
Faraday.new(url: @api_endpoint) do |faraday| | ||
faraday.adapter :net_http | ||
end | ||
end | ||
|
||
# Create a signature for request | ||
def signature(params = '') | ||
hash = OpenSSL::HMAC.digest('sha256', @api_key, params) | ||
Base64.strict_encode64(hash) | ||
end | ||
|
||
def init_default_headers(request) | ||
request.headers['client-type'] = @client_type_header | ||
request.headers['Accept'] = 'application/json' | ||
request.headers['Content-Type'] = 'application/json' | ||
request.headers['api-auth-id'] = @api_id | ||
request.headers['api-auth-signature'] = signature(request.params.to_query) | ||
end | ||
|
||
# Make a HTTP GET request | ||
# | ||
# @param url [String] The path, relative to {api_endpoint} | ||
# @param parameters [Hash] Query params for request | ||
# @return [Faraday::Response] | ||
def get(url, parameters = {}, headers = {}, skip_status_check = false) | ||
response = connection.get do |request| | ||
request.url "#{api_endpoint}#{url}" | ||
request.params = parameters | ||
|
||
# Set headers | ||
init_default_headers(request) | ||
|
||
# Assign more custom headers | ||
headers.each do |key, value| | ||
request.headers[key] = value | ||
end | ||
end | ||
|
||
on_complete(response) unless skip_status_check | ||
response | ||
end | ||
|
||
# # Make a HTTP POST request | ||
# # | ||
# # @param url [String] The path, relative to {#api_endpoint} | ||
# # @param parameters [Hash] Query params for request | ||
# # @return [Faraday::Response] | ||
# def post(url, parameters = {}) | ||
# response = connection.post do |req| | ||
# req.url "#{api_endpoint}#{url}" | ||
# req.headers['Content-Type'] = 'application/json' | ||
# req.body = parameters.to_json | ||
# end | ||
# on_complete(response) | ||
# response | ||
# end | ||
|
||
# # Make a HTTP PATCH request | ||
# # | ||
# # @param url [String] The path, relative to {#api_endpoint} | ||
# # @param parameters [Hash] Query params for request | ||
# # @return [Faraday::Response] | ||
# def patch(url, parameters = {}) | ||
# response = connection.patch do |req| | ||
# req.url "#{api_endpoint}#{url}" | ||
# req.headers['Content-Type'] = 'application/json' | ||
# req.body = parameters.to_json | ||
# end | ||
# on_complete(response) | ||
# response | ||
# end | ||
|
||
# # Make a HTTP DELETE request | ||
# # | ||
# # @param url [String] The path, relative to {#api_endpoint} | ||
# # @param parameters [Hash] Query params for request | ||
# # @return [Faraday::Response] | ||
# def delete(url, parameters = {}) | ||
# response = connection.delete do |req| | ||
# req.url "#{api_endpoint}#{url}" | ||
# req.headers['Content-Type'] = 'application/json' | ||
# req.body = parameters.to_json | ||
# end | ||
# on_complete(response) | ||
# response | ||
# end | ||
|
||
# Show details of your Platform. | ||
# | ||
# @see https://reference.Unleashed.com/#show-marketplace | ||
# | ||
# @return [Hash] | ||
def marketplace | ||
JSON.parse(get('marketplace').body)['marketplaces'] | ||
end | ||
|
||
# Available resources for {Client} | ||
# | ||
# @return [Hash] | ||
def self.resources | ||
{ | ||
customers: CustomerResource | ||
} | ||
end | ||
|
||
# Catch calls for resources | ||
# | ||
def method_missing(name, *args, &block) | ||
if self.class.resources.keys.include?(name) | ||
resources[name] ||= self.class.resources[name].new(self) | ||
resources[name] | ||
else | ||
super | ||
end | ||
end | ||
|
||
# Resources being currently used | ||
# | ||
# @return [Hash] | ||
def resources | ||
@resources ||= {} | ||
end | ||
|
||
private | ||
|
||
def on_complete(response) | ||
fail Unleashed::Error.from_response(response, @errors_format) unless response.success? | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
module Unleashed | ||
# Configuration options for {Client}, defaulting to values in {Default}. | ||
module Configurable | ||
attr_accessor :api_domain, :api_id, :api_key, :client_type_header, :errors_format | ||
|
||
class << self | ||
# List of configurable keys for {Unleashed::Client}. | ||
# | ||
# @return [Array] of option keys | ||
def keys | ||
@keys ||= [ | ||
:api_domain, | ||
:api_id, | ||
:api_key, | ||
:client_type_header, | ||
:errors_format | ||
] | ||
end | ||
end | ||
|
||
# Reset configuration options to default values. | ||
def reset! | ||
Unleashed::Configurable.keys.each do |key| | ||
instance_variable_set(:"@#{key}", Unleashed::Default.options[key]) | ||
end | ||
|
||
self | ||
end | ||
|
||
alias setup reset! | ||
|
||
# API endpoint to be used by {Unleashed::Client}. | ||
# Built from {#api_domain} | ||
# | ||
# @return [String] | ||
def api_endpoint | ||
"https://#{@api_domain}/" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
module Unleashed | ||
# Default configuration options for {Client} | ||
module Default | ||
# Default API domain | ||
API_DOMAIN = 'api.unleashedsoftware.com'.freeze | ||
# Default client_type_header | ||
CLIENT_TYPE_HEADER = 'API-Sandbox'.freeze | ||
|
||
class << self | ||
# Configuration options. | ||
# | ||
# @return [Hash] | ||
def options | ||
Hash[Unleashed::Configurable.keys.map { |key| [key, send(key)] }] | ||
end | ||
|
||
# Default API domain from ENV or {API_DOMAIN}. | ||
# | ||
# @return [String] | ||
def api_domain | ||
ENV['UNLEASHED_API_DOMAIN'] || API_DOMAIN | ||
end | ||
|
||
# Default api_id from ENV. | ||
# | ||
# @return [String] | ||
def api_id | ||
ENV['UNLEASHED_API_ID'] | ||
end | ||
|
||
# Default api_key from ENV. | ||
# | ||
# @return [String] | ||
def api_key | ||
ENV['UNLEASHED_API_KEY'] | ||
end | ||
|
||
# Default client_type_header from ENV. | ||
# | ||
# @return [String] | ||
def client_type_header | ||
ENV['UNLEASHED_CLIENT_TYPE_HEADER'] || CLIENT_TYPE_HEADER | ||
end | ||
|
||
# Default errors_format from ENV. | ||
# | ||
# @return [String] | ||
def errors_format | ||
ENV['UNLEASHED_ERRORS_FORMAT'] || 'processed' | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
module Unleashed | ||
# Custom error class for rescuing from all Unleashed errors | ||
class Error < StandardError | ||
# Returns the appropriate Unleashed::Error subclass based on status | ||
# | ||
# @param [Faraday::Response] response Faraday HTTP response | ||
# @return [Unleashed::Error] | ||
def self.from_response(response, errors_format = nil) | ||
klass = case response.status | ||
when 400 then Unleashed::BadRequest | ||
when 401 then Unleashed::Unauthorized | ||
when 403 then Unleashed::Forbidden | ||
when 404 then Unleashed::NotFound | ||
when 405 then Unleashed::MethodNotAllowed | ||
when 406 then Unleashed::NotAcceptable | ||
when 409 then Unleashed::Conflict | ||
when 422 then Unleashed::UnprocessableEntity | ||
when 400..499 then Unleashed::ClientError | ||
when 500 then Unleashed::InternalServerError | ||
when 501 then Unleashed::NotImplemented | ||
when 502 then Unleashed::BadGateway | ||
when 503 then Unleashed::ServiceUnavailable | ||
when 500..599 then Unleashed::ServerError | ||
end | ||
klass ? klass.new(response, errors_format) : new(response, errors_format) | ||
end | ||
|
||
def initialize(response = nil, errors_format = nil) | ||
@response = response | ||
@errors_format = errors_format | ||
super(build_error_message) | ||
end | ||
|
||
private | ||
|
||
def build_error_message | ||
return nil if @response.nil? || @response.body.nil? | ||
|
||
case @errors_format | ||
when 'raw' | ||
@response.body | ||
else | ||
json_response = JSON.parse(@response.body) | ||
message = '' | ||
message << json_response['message'] if json_response.key?('message') | ||
|
||
if json_response.key?('errors') | ||
message << json_response['errors'].map { |attribute, content| "#{attribute}: #{content}" }.join(', ') | ||
end | ||
|
||
message | ||
end | ||
end | ||
end | ||
|
||
# Raised on errors in the 400-499 range | ||
class ClientError < Error; end | ||
|
||
# Raised when Unleashed returns a 400 HTTP status code | ||
class BadRequest < ClientError; end | ||
|
||
# Raised when Unleashed returns a 401 HTTP status code | ||
class Unauthorized < ClientError; end | ||
|
||
# Raised when Unleashed returns a 403 HTTP status code | ||
class Forbidden < ClientError; end | ||
|
||
# Raised when Unleashed returns a 404 HTTP status code | ||
class NotFound < ClientError; end | ||
|
||
# Raised when Unleashed returns a 405 HTTP status code | ||
class MethodNotAllowed < ClientError; end | ||
|
||
# Raised when Unleashed returns a 406 HTTP status code | ||
class NotAcceptable < ClientError; end | ||
|
||
# Raised when Unleashed returns a 409 HTTP status code | ||
class Conflict < ClientError; end | ||
|
||
# Raised when Unleashed returns a 422 HTTP status code | ||
class UnprocessableEntity < ClientError; end | ||
|
||
# Raised on errors in the 500-599 range | ||
class ServerError < Error; end | ||
|
||
# Raised when Unleashed returns a 500 HTTP status code | ||
class InternalServerError < ServerError; end | ||
|
||
# Raised when Unleashed returns a 501 HTTP status code | ||
class NotImplemented < ServerError; end | ||
|
||
# Raised when Unleashed returns a 502 HTTP status code | ||
class BadGateway < ServerError; end | ||
|
||
# Raised when Unleashed returns a 503 HTTP status code | ||
class ServiceUnavailable < ServerError; end | ||
end |
Oops, something went wrong.